diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a9c9d7a26e..e7e6221806 100755 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,6 +20,7 @@ examples/rust/ @rapidsai/cuvs-rust-codeowners #docs code owners docs/ @rapidsai/cuvs-docs-codeowners +fern/ @rapidsai/cuvs-docs-codeowners #cmake code owners CMakeLists.txt @rapidsai/cuvs-cmake-codeowners diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c031c3709d..1dec1043d2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -229,7 +229,6 @@ jobs: uses: ./.github/workflows/publish-rust.yaml docs-build: if: github.ref_type == 'branch' - needs: python-build permissions: actions: read contents: read diff --git a/.github/workflows/check-c-abi.yaml b/.github/workflows/check-c-abi.yaml index e93294b160..a594c48f44 100644 --- a/.github/workflows/check-c-abi.yaml +++ b/.github/workflows/check-c-abi.yaml @@ -128,5 +128,5 @@ jobs: - The changes are documented in the changelog - Migration guide is provided for users - For more information, see the [C ABI documentation](../docs/source/c_developer_guide.md).` + For more information, see the [C API documentation](../fern/pages/c_api/index.md).` }); diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 5f881166af..0ccd5807ac 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -134,6 +134,7 @@ jobs: - '!ci/test_wheel_cuvs.sh' - '!ci/validate_wheel.sh' - '!docs/**' + - '!fern/**' - '!go/**' - '!img/**' - '!java/**' @@ -170,6 +171,7 @@ jobs: - '!ci/validate_wheel.sh' - '!Dockerfile' - '!docs/**' + - '!fern/**' - '!img/**' - '!notebooks/**' - '!python/**' @@ -209,6 +211,7 @@ jobs: - '!Dockerfile' - '!README.md' - '!docs/**' + - '!fern/**' - '!go/**' - '!img/**' - '!java/**' @@ -253,6 +256,7 @@ jobs: - '!cpp/.clang-tidy' - '!cpp/doxygen/**' - '!docs/**' + - '!fern/**' - '!java/**' - '!go/**' - '!img/**' @@ -292,6 +296,7 @@ jobs: - '!ci/test_wheel_cuvs.sh' - '!ci/validate_wheel.sh' - '!docs/**' + - '!fern/**' - '!go/**' - '!img/**' - '!java/**' @@ -332,6 +337,7 @@ jobs: - '!ci/test_wheel_cuvs.sh' - '!ci/validate_wheel.sh' - '!docs/**' + - '!fern/**' - '!img/**' - '!java/**' - '!notebooks/**' @@ -581,7 +587,6 @@ jobs: container_image: "rapidsai/ci-conda:26.06-cuda${{ matrix.CUDA_VER }}-${{ matrix.LINUX_VER }}-py${{ matrix.PY_VER }}" script: "ci/build_go.sh" docs-build: - needs: conda-python-build permissions: actions: read contents: read diff --git a/build.sh b/build.sh index e39f5be5e2..f5260ecd59 100755 --- a/build.sh +++ b/build.sh @@ -67,8 +67,7 @@ HELP="$0 [ ...] [ ...] [--cmake-args=\"\"] [--cache-tool=/dev/null || nproc) +fi BUILD_ABI=${BUILD_ABI:=ON} # Default to Ninja if generator is not specified @@ -371,7 +372,7 @@ fi ################################################################################ # Configure for building all C++ targets -if (( NUMARGS == 0 )) || hasArg libcuvs || hasArg docs || hasArg tests || hasArg bench-prims || hasArg bench-ann || hasArg examples; then +if (( NUMARGS == 0 )) || hasArg libcuvs || hasArg tests || hasArg bench-prims || hasArg bench-ann || hasArg examples; then COMPILE_LIBRARY=ON if [[ "${BUILD_SHARED_LIBS}" != "OFF" ]]; then CMAKE_TARGET+=("cuvs") @@ -535,13 +536,8 @@ export RAPIDS_VERSION_MAJOR_MINOR if hasArg docs; then set -x - cd "${DOXYGEN_BUILD_DIR}" - doxygen Doxyfile - cd "${SPHINX_BUILD_DIR}" - make html - cd "${REPODIR}"/rust - cargo doc -p cuvs --no-deps - rsync -av "${RUST_BUILD_DIR}"/doc/ "${SPHINX_BUILD_DIR}"/build/html/_static/rust + cd "${REPODIR}" + "${FERN_DOCS_DIR}/build_docs.sh" "${FERN_DOCS_MODE:-check}" fi ################################################################################ diff --git a/ci/build_docs.sh b/ci/build_docs.sh index 65c8f29f8a..3d96b93435 100755 --- a/ci/build_docs.sh +++ b/ci/build_docs.sh @@ -4,25 +4,16 @@ set -euo pipefail -rapids-logger "Downloading artifacts from previous jobs" -CPP_CHANNEL=$(rapids-download-conda-from-github cpp) -PYTHON_CHANNEL=$(rapids-download-from-github "$(rapids-package-name "conda_python" cuvs --stable --cuda "$RAPIDS_CUDA_VERSION")") - -rapids-logger "Create test conda environment" +rapids-logger "Create docs conda environment" . /opt/conda/etc/profile.d/conda.sh rapids-logger "Configuring conda strict channel priority" conda config --set channel_priority strict -RAPIDS_VERSION_MAJOR_MINOR="$(rapids-version-major-minor)" -export RAPIDS_VERSION_MAJOR_MINOR - rapids-dependency-file-generator \ --output conda \ --file-key docs \ --matrix "cuda=${RAPIDS_CUDA_VERSION%.*};arch=$(arch);py=${RAPIDS_PY_VERSION}" \ - --prepend-channel "${CPP_CHANNEL}" \ - --prepend-channel "${PYTHON_CHANNEL}" \ | tee env.yaml rapids-mamba-retry env create --yes -f env.yaml -n docs @@ -35,27 +26,40 @@ set -eu rapids-print-env -RAPIDS_DOCS_DIR="$(mktemp -d)" -export RAPIDS_DOCS_DIR - -rapids-logger "Build CPP docs" -pushd cpp/doxygen -doxygen Doxyfile -popd - -rapids-logger "Build Rust docs" -pushd rust -LIBCLANG_PATH=$(dirname "$(find "$CONDA_PREFIX" -name libclang.so | head -n 1)") -export LIBCLANG_PATH -cargo doc -p cuvs --no-deps -popd - -rapids-logger "Build Python docs" -pushd docs -make dirhtml -mv ../rust/target/doc ./build/dirhtml/_static/rust -mkdir -p "${RAPIDS_DOCS_DIR}/cuvs/"html -mv build/dirhtml/* "${RAPIDS_DOCS_DIR}/cuvs/html" -popd - -RAPIDS_VERSION_NUMBER="${RAPIDS_VERSION_MAJOR_MINOR}" rapids-upload-docs +rapids-logger "Validate Fern docs" + +find_pr_number() { + local ref + for ref in "${RAPIDS_REF_NAME:-}" "${GITHUB_REF:-}" "${GITHUB_REF_NAME:-}"; do + if [[ "${ref}" =~ (^|/)pull-request/([0-9]+)$ ]]; then + echo "${BASH_REMATCH[2]}" + return 0 + fi + if [[ "${ref}" =~ ^refs/pull/([0-9]+)/ ]]; then + echo "${BASH_REMATCH[1]}" + return 0 + fi + if [[ "${ref}" =~ ^([0-9]+)/merge$ ]]; then + echo "${BASH_REMATCH[1]}" + return 0 + fi + done +} + +FERN_DOCS_MODE="${FERN_DOCS_MODE:-check}" +FERN_DOCS_ARGS=() + +if [[ "${FERN_DOCS_MODE}" == "preview" ]]; then + FERN_PREVIEW_ID="${FERN_DOCS_PREVIEW_ID:-}" + if [[ -z "${FERN_PREVIEW_ID}" ]]; then + PR_NUMBER="$(find_pr_number || true)" + if [[ -n "${PR_NUMBER}" ]]; then + FERN_PREVIEW_ID="pr-${PR_NUMBER}" + fi + fi + if [[ -n "${FERN_PREVIEW_ID}" ]]; then + FERN_DOCS_ARGS+=(--id "${FERN_PREVIEW_ID}") + fi +fi + +fern/build_docs.sh "${FERN_DOCS_MODE}" "${FERN_DOCS_ARGS[@]}" diff --git a/ci/release/update-version.sh b/ci/release/update-version.sh index 4cb8591231..f36c14f771 100755 --- a/ci/release/update-version.sh +++ b/ci/release/update-version.sh @@ -139,14 +139,14 @@ if [[ "${RUN_CONTEXT}" == "main" ]]; then : elif [[ "${RUN_CONTEXT}" == "release" ]]; then # In release context, use release branch for documentation links (word boundaries to avoid partial matches) - sed_runner "/rapidsai\\/cuvs/ s|\\bmain\\b|release/${NEXT_SHORT_TAG}|g" docs/source/developer_guide.md + sed_runner "/rapidsai\\/cuvs/ s|\\bmain\\b|release/${NEXT_SHORT_TAG}|g" fern/pages/developer_guide.md sed_runner "s|\\bmain\\b|release/${NEXT_SHORT_TAG}|g" README.md # Only update the GitHub URL, not the main() function sed_runner "s|/cuvs/blob/\\bmain\\b/|/cuvs/blob/release/${NEXT_SHORT_TAG}/|g" python/cuvs_bench/cuvs_bench/plot/__main__.py fi # Update cuvs-bench Docker image references (version-only, not branch-related) -sed_runner "s|rapidsai/cuvs-bench:[0-9][0-9].[0-9][0-9]|rapidsai/cuvs-bench:${NEXT_SHORT_TAG}|g" docs/source/cuvs_bench/index.rst +sed_runner "s|rapidsai/cuvs-bench:[0-9][0-9].[0-9][0-9]|rapidsai/cuvs-bench:${NEXT_SHORT_TAG}|g" fern/pages/cuvs_bench/index.md # Version references (not branch-related) sed_runner "s|=[0-9][0-9].[0-9][0-9]|=${NEXT_SHORT_TAG}|g" README.md diff --git a/conda/environments/all_cuda-129_arch-aarch64.yaml b/conda/environments/all_cuda-129_arch-aarch64.yaml index 0a473a210f..03a4c294f5 100644 --- a/conda/environments/all_cuda-129_arch-aarch64.yaml +++ b/conda/environments/all_cuda-129_arch-aarch64.yaml @@ -6,7 +6,6 @@ channels: - conda-forge dependencies: - _go_select *=cgo -- breathe>=4.35.0 - c-compiler - clang-tools==20.1.8 - clang==20.1.8 @@ -21,11 +20,8 @@ dependencies: - cxx-compiler - cython>=3.2.2 - dlpack>=0.8,<1.0 -- doxygen>=1.8.20 - gcc_linux-aarch64=14.* - go -- graphviz -- ipython - libclang==20.1.8 - libcublas-dev - libcurand-dev @@ -37,22 +33,16 @@ dependencies: - make - nccl>=2.19 - ninja +- nodejs>=22 - numpy>=1.23,<3.0 -- numpydoc - openblas - pre-commit - pylibraft==26.6.*,>=0.0.0a0 - pytest - pytest-cov - rapids-build-backend>=0.4.0,<0.5.0 -- recommonmark - rust - scikit-build-core>=0.11.0 - scikit-learn>=1.5 -- sphinx-copybutton -- sphinx-markdown-tables -- sphinx>=8.0.0 - sysroot_linux-aarch64==2.28 -- pip: - - nvidia-sphinx-theme name: all_cuda-129_arch-aarch64 diff --git a/conda/environments/all_cuda-129_arch-x86_64.yaml b/conda/environments/all_cuda-129_arch-x86_64.yaml index 08e3c3f4e5..a2185d5d49 100644 --- a/conda/environments/all_cuda-129_arch-x86_64.yaml +++ b/conda/environments/all_cuda-129_arch-x86_64.yaml @@ -6,7 +6,6 @@ channels: - conda-forge dependencies: - _go_select *=cgo -- breathe>=4.35.0 - c-compiler - clang-tools==20.1.8 - clang==20.1.8 @@ -21,11 +20,8 @@ dependencies: - cxx-compiler - cython>=3.2.2 - dlpack>=0.8,<1.0 -- doxygen>=1.8.20 - gcc_linux-64=14.* - go -- graphviz -- ipython - libclang==20.1.8 - libcublas-dev - libcurand-dev @@ -36,22 +32,16 @@ dependencies: - make - nccl>=2.19 - ninja +- nodejs>=22 - numpy>=1.23,<3.0 -- numpydoc - openblas - pre-commit - pylibraft==26.6.*,>=0.0.0a0 - pytest - pytest-cov - rapids-build-backend>=0.4.0,<0.5.0 -- recommonmark - rust - scikit-build-core>=0.11.0 - scikit-learn>=1.5 -- sphinx-copybutton -- sphinx-markdown-tables -- sphinx>=8.0.0 - sysroot_linux-64==2.28 -- pip: - - nvidia-sphinx-theme name: all_cuda-129_arch-x86_64 diff --git a/conda/environments/all_cuda-132_arch-aarch64.yaml b/conda/environments/all_cuda-132_arch-aarch64.yaml index 46bbfe1cca..2ae260033a 100644 --- a/conda/environments/all_cuda-132_arch-aarch64.yaml +++ b/conda/environments/all_cuda-132_arch-aarch64.yaml @@ -6,7 +6,6 @@ channels: - conda-forge dependencies: - _go_select *=cgo -- breathe>=4.35.0 - c-compiler - clang-tools==20.1.8 - clang==20.1.8 @@ -21,11 +20,8 @@ dependencies: - cxx-compiler - cython>=3.2.2 - dlpack>=0.8,<1.0 -- doxygen>=1.8.20 - gcc_linux-aarch64=14.* - go -- graphviz -- ipython - libclang==20.1.8 - libcublas-dev - libcurand-dev @@ -37,22 +33,16 @@ dependencies: - make - nccl>=2.19 - ninja +- nodejs>=22 - numpy>=1.23,<3.0 -- numpydoc - openblas - pre-commit - pylibraft==26.6.*,>=0.0.0a0 - pytest - pytest-cov - rapids-build-backend>=0.4.0,<0.5.0 -- recommonmark - rust - scikit-build-core>=0.11.0 - scikit-learn>=1.5 -- sphinx-copybutton -- sphinx-markdown-tables -- sphinx>=8.0.0 - sysroot_linux-aarch64==2.28 -- pip: - - nvidia-sphinx-theme name: all_cuda-132_arch-aarch64 diff --git a/conda/environments/all_cuda-132_arch-x86_64.yaml b/conda/environments/all_cuda-132_arch-x86_64.yaml index c529642139..1e9577e896 100644 --- a/conda/environments/all_cuda-132_arch-x86_64.yaml +++ b/conda/environments/all_cuda-132_arch-x86_64.yaml @@ -6,7 +6,6 @@ channels: - conda-forge dependencies: - _go_select *=cgo -- breathe>=4.35.0 - c-compiler - clang-tools==20.1.8 - clang==20.1.8 @@ -21,11 +20,8 @@ dependencies: - cxx-compiler - cython>=3.2.2 - dlpack>=0.8,<1.0 -- doxygen>=1.8.20 - gcc_linux-64=14.* - go -- graphviz -- ipython - libclang==20.1.8 - libcublas-dev - libcurand-dev @@ -36,22 +32,16 @@ dependencies: - make - nccl>=2.19 - ninja +- nodejs>=22 - numpy>=1.23,<3.0 -- numpydoc - openblas - pre-commit - pylibraft==26.6.*,>=0.0.0a0 - pytest - pytest-cov - rapids-build-backend>=0.4.0,<0.5.0 -- recommonmark - rust - scikit-build-core>=0.11.0 - scikit-learn>=1.5 -- sphinx-copybutton -- sphinx-markdown-tables -- sphinx>=8.0.0 - sysroot_linux-64==2.28 -- pip: - - nvidia-sphinx-theme name: all_cuda-132_arch-x86_64 diff --git a/dependencies.yaml b/dependencies.yaml index 538c104757..8a82a598c2 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -453,17 +453,7 @@ dependencies: common: - output_types: [conda] packages: - - breathe>=4.35.0 - - doxygen>=1.8.20 - - graphviz - - ipython - - numpydoc - - recommonmark - - sphinx>=8.0.0 - - sphinx-copybutton - - sphinx-markdown-tables - - pip: - - nvidia-sphinx-theme + - nodejs>=22 rust: common: - output_types: [conda] diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 86a635a54d..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -W -SPHINXBUILD = sphinx-build -SPHINXPROJ = cuvs -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help -v "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md index 639961ea37..6207fe85df 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,14 +1,35 @@ # Building Documentation -## Building locally: -#### [Build and install cuVS](source/build.md) +The cuVS documentation is a Fern project in [../fern](../fern). -#### Generate the docs -```shell script -bash build.sh docs +Fern requires Node.js 22 or newer. If the docs fail with an error such as `SyntaxError: Unexpected token '.'`, check `node --version` and activate a newer Node.js runtime. + +## Preview locally + +```bash +fern/build_docs.sh dev +``` + +Fern serves the preview at [http://localhost:3000](http://localhost:3000) by default. + +## Validate + +```bash +fern/build_docs.sh check ``` -#### Once the process finishes, documentation can be found in build/html -```shell script -xdg-open build/html/index.html` +The Fern build refreshes the C, C++, Python, Java, Rust, and Go API reference pages from the source tree before validating. + +## Publish + +Create a Fern preview deployment: + +```bash +fern/build_docs.sh preview +``` + +Publish the production docs site: + +```bash +fern/build_docs.sh publish ``` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index ec3fa36436..0000000000 --- a/docs/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build -set SPHINXPROJ=cuvs - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/source/_static/collapse_overloads.js b/docs/source/_static/collapse_overloads.js deleted file mode 100644 index 2ec2e710fb..0000000000 --- a/docs/source/_static/collapse_overloads.js +++ /dev/null @@ -1,67 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - const toc = document.querySelector(".bd-toc-nav"); - if (!toc) return; - - // Get all TOC links - const links = toc.querySelectorAll("a"); - - const seen = new Set(); - links.forEach(link => { - let text = link.textContent.trim(); - let norm = text.replace(/\(\)$/, ""); // strip trailing () - - if (seen.has(norm)) { - // hide duplicate - link.parentElement.style.display = "none"; - } else { - seen.add(norm); - } - }); - }); - -document.addEventListener("DOMContentLoaded", () => { - const toc = document.querySelector(".toctree-wrapper"); - if (!toc) return; - - const leaf_traversal_fn = (leaf) => { - try { - const links = leaf.querySelectorAll("a"); - if (!links) return; - const seen = new Set(); - links.forEach(link => { - let text = link.textContent.trim(); - let norm = text.replace(/\(\)$/, ""); // strip trailing () - - if (seen.has(norm)) { - // hide duplicate - link.parentElement.style.display = "none"; - } else { - seen.add(norm); - } - }); - } catch (error) { - console.error(error); - } - }; - queue = [toc.querySelector("li")]; - while (queue.length > 0) { - const tree = queue.shift(); - try { - if (tree.childElementCount > 1 && - tree.firstChild.hasAttribute("href") && - tree.firstChild.attributes["href"].value.includes("#")) { - leaf_traversal_fn(tree.childNodes[1]); - } else { - const child = tree.querySelector("li"); - if (child) { - queue.push(child); - } - } - } catch (error) { - console.error(error); - } - if (tree.nextElementSibling) { - queue.push(tree.nextElementSibling); - } - } - }); diff --git a/docs/source/_static/references.css b/docs/source/_static/references.css deleted file mode 100644 index b8e1c631b8..0000000000 --- a/docs/source/_static/references.css +++ /dev/null @@ -1,36 +0,0 @@ - -/* Fix references to not look like parameters */ -dl.citation > dt.label { - display: unset !important; - float: left !important; - border: unset !important; - background: unset !important; - padding: unset !important; - margin: unset !important; - font-size: unset !important; - line-height: unset !important; - padding-right: 0.5rem !important; -} - -/* Add opening bracket */ -dl.citation > dt.label > span::before { - content: "["; -} - -/* Add closing bracket */ -dl.citation > dt.label > span::after { - content: "]"; -} - -/* Highlight math formulas in a box */ -div.math { - background-color: #f8f9fa !important; - border-top: 1px solid #e9ecef !important; - border-bottom: 1px solid #e9ecef !important; - border-left: none !important; - border-right: none !important; - border-radius: 0 !important; - padding: 1rem 1.25rem !important; - margin: 1rem 0 !important; - overflow-x: auto !important; -} diff --git a/docs/source/advanced_topics.rst b/docs/source/advanced_topics.rst deleted file mode 100644 index 4171845af5..0000000000 --- a/docs/source/advanced_topics.rst +++ /dev/null @@ -1,22 +0,0 @@ -Advanced Topics -=============== - -- `Just-in-Time Compilation`_ - -Just-in-Time Compilation ------------------------- -cuVS uses the Just-in-Time (JIT) `Link-Time Optimization (LTO) `_ compilation technology to compile certain kernels. When a JIT compilation is triggered, cuVS will compile the kernel for your architecture and automatically cache it in-memory and on-disk. The validity of the cache is as follows: - -1. In-memory cache is valid for the lifetime of the process. -2. On-disk cache is valid until a CUDA driver upgrade is performed. The cache can be portably shared between machines in network or cloud storage and we strongly recommend that you store the cache in a persistent location. For more details on how to configure the on-disk cache, look at CUDA documentation on `JIT Compilation `_. Specifically, the environment variables of interest are: `CUDA_CACHE_PATH` and `CUDA_CACHE_MAX_SIZE`. - - -Thus, the JIT compilation is a one-time cost and you can expect no loss in real performance after the first compilation. We recommend that you run a "warmup" to trigger the JIT compilation before the actual usage. - -Currently, the following capabilities will trigger a JIT compilation: -- IVF Flat search APIs: :doc:`cuvs::neighbors::ivf_flat::search() ` - -.. toctree:: - :maxdepth: 2 - - jit_lto_guide diff --git a/docs/source/api_basics.rst b/docs/source/api_basics.rst deleted file mode 100644 index 5ffb1da630..0000000000 --- a/docs/source/api_basics.rst +++ /dev/null @@ -1,90 +0,0 @@ -cuVS API Basics -=============== - -- `Memory management`_ -- `Resource management`_ - -Memory management ------------------ - -Centralized memory management allows flexible configuration of allocation strategies, such as sharing the same CUDA memory pool across library boundaries. cuVS uses the `RMM `_ library, which eases the burden of configuring different allocation strategies globally across GPU-accelerated libraries. - -RMM currently has APIs for C++ and Python. - -C++ -^^^ - -Here's an example of configuring RMM to use a pool allocator in C++ (derived from the RMM example `here `__): - -.. code-block:: c++ - - rmm::mr::cuda_memory_resource cuda_mr; - // Construct a resource that uses a coalescing best-fit pool allocator - // With the pool initially half of available device memory - auto initial_size = rmm::percent_of_free_device_memory(50); - rmm::mr::pool_memory_resource pool_mr{cuda_mr, initial_size}; - rmm::mr::set_current_device_resource(pool_mr); - auto mr = rmm::mr::get_current_device_resource_ref(); - -Python -^^^^^^ - -And the corresponding code in Python (derived from the RMM example `here `__): - -.. code-block:: python - - import rmm - pool = rmm.mr.PoolMemoryResource( - rmm.mr.CudaMemoryResource(), - initial_pool_size=2**30, - maximum_pool_size=2**32) - rmm.mr.set_current_device_resource(pool) - - -Resource management -------------------- - -cuVS uses an API from the `RAFT `_ library of ML and data mining primitives to centralize and reuse expensive resources, such as memory management. The below code examples demonstrate how to create these resources for use throughout this guide. - -See RAFT's `resource API documentation `_ for more information. - -C -^ - -.. code-block:: c - - #include - #include - - cuvsResources_t res; - cuvsResourcesCreate(&res); - - // ... do some processing ... - - cuvsResourcesDestroy(res); - -C++ -^^^ - -.. code-block:: c++ - - #include - - raft::device_resources res; - -Python -^^^^^^ - -.. code-block:: python - - import pylibraft - - res = pylibraft.common.DeviceResources() - - -Rust -^^^^ - -.. code-block:: rust - - let res = cuvs::Resources::new()?; diff --git a/docs/source/api_docs.rst b/docs/source/api_docs.rst deleted file mode 100644 index 68d184c72c..0000000000 --- a/docs/source/api_docs.rst +++ /dev/null @@ -1,13 +0,0 @@ -API Reference -============= - -.. toctree:: - :maxdepth: 3 - - c_api.rst - cpp_api.rst - python_api.rst - rust_api/index.rst - -* :ref:`genindex` -* :ref:`search` diff --git a/docs/source/api_interoperability.rst b/docs/source/api_interoperability.rst deleted file mode 100644 index 097025aee7..0000000000 --- a/docs/source/api_interoperability.rst +++ /dev/null @@ -1,106 +0,0 @@ -Interoperability -================ - -DLPack (C) -^^^^^^^^^^ - -Approximate nearest neighbor (ANN) indexes provide an interface to build and search an index via a C API. `DLPack v0.8 `_, a tensor interface framework, is used as the standard to interact with our C API. - -Representing a tensor with DLPack is simple, as it is a POD struct that stores information about the tensor at runtime. At the moment, `DLManagedTensor` from DLPack v0.8 is compatible with out C API however we will soon upgrade to `DLManagedTensorVersioned` from DLPack v1.0 as it will help us maintain ABI and API compatibility. - -Here's an example on how to represent device memory using `DLManagedTensor`: - -.. code-block:: c - - #include - - // Create data representation in host memory - float dataset[2][1] = {{0.2, 0.1}}; - // copy data to device memory - float *dataset_dev; - cuvsRMMAlloc(&dataset_dev, sizeof(float) * 2 * 1); - cudaMemcpy(dataset_dev, dataset, sizeof(float) * 2 * 1, cudaMemcpyDefault); - - // Use DLPack for representing the data as a tensor - DLManagedTensor dataset_tensor; - dataset_tensor.dl_tensor.data = dataset; - dataset_tensor.dl_tensor.device.device_type = kDLCUDA; - dataset_tensor.dl_tensor.ndim = 2; - dataset_tensor.dl_tensor.dtype.code = kDLFloat; - dataset_tensor.dl_tensor.dtype.bits = 32; - dataset_tensor.dl_tensor.dtype.lanes = 1; - int64_t dataset_shape[2] = {2, 1}; - dataset_tensor.dl_tensor.shape = dataset_shape; - dataset_tensor.dl_tensor.strides = nullptr; - - // free memory after use - cuvsRMMFree(dataset_dev); - -Please refer to `cuVS C API documentation `_ to learn more. - -Multi-dimensional span (C++) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -cuVS is built on top of the GPU-accelerated machine learning and data mining primitives in the `RAFT `_ library. Most of the C++ APIs in cuVS accept `mdspan `_ multi-dimensional array view for representing data in higher dimensions similar to the `ndarray` in the Numpy Python library. RAFT also contains the corresponding owning `mdarray` structure, which simplifies the allocation and management of multi-dimensional data in both host and device (GPU) memory. - -The `mdarray` is an owning object that forms a convenience layer over RMM and can be constructed in RAFT using a number of different helper functions: - -.. code-block:: c++ - - #include - - int n_rows = 10; - int n_cols = 10; - - auto scalar = raft::make_device_scalar(handle, 1.0); - auto vector = raft::make_device_vector(handle, n_cols); - auto matrix = raft::make_device_matrix(handle, n_rows, n_cols); - -The `mdspan` is a lightweight non-owning view that can wrap around any pointer, maintaining shape, layout, and indexing information for accessing elements. - -We can construct `mdspan` instances directly from the above `mdarray` instances: - -.. code-block:: c++ - - // Scalar mdspan on device - auto scalar_view = scalar.view(); - - // Vector mdspan on device - auto vector_view = vector.view(); - - // Matrix mdspan on device - auto matrix_view = matrix.view(); - -Since the `mdspan` is just a lightweight wrapper, we can also construct it from the underlying data handles in the `mdarray` instances above. We use the extent to get information about the `mdarray` or `mdspan`'s shape. - -.. code-block:: c++ - - #include - - auto scalar_view = raft::make_device_scalar_view(scalar.data_handle()); - auto vector_view = raft::make_device_vector_view(vector.data_handle(), vector.extent(0)); - auto matrix_view = raft::make_device_matrix_view(matrix.data_handle(), matrix.extent(0), matrix.extent(1)); - -Of course, RAFT's `mdspan`/`mdarray` APIs aren't just limited to the `device`. You can also create `host` variants: - -.. code-block:: c++ - - #include - #include - - int n_rows = 10; - int n_cols = 10; - - auto scalar = raft::make_host_scalar(handle, 1.0); - auto vector = raft::make_host_vector(handle, n_cols); - auto matrix = raft::make_host_matrix(handle, n_rows, n_cols); - - auto scalar_view = raft::make_host_scalar_view(scalar.data_handle()); - auto vector_view = raft::make_host_vector_view(vector.data_handle(), vector.extent(0)); - auto matrix_view = raft::make_host_matrix_view(matrix.data_handle(), matrix.extent(0), matrix.extent(1)); - -Please refer to RAFT's `mdspan documentation `_ to learn more. - - -CUDA array interface (Python) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/build.rst b/docs/source/build.rst deleted file mode 100644 index 00b0a70e2c..0000000000 --- a/docs/source/build.rst +++ /dev/null @@ -1,285 +0,0 @@ -Installation -============ - -The cuVS software development kit provides APIs for C, C++, Python, and Rust languages. This guide outlines how to install the pre-compiled packages, build it from source, and use it in downstream applications. - -- `Installing pre-compiled packages`_ - - * `C, C++, and Python through Conda`_ - - * `Python through Pip`_ - - * `Tarball`_ - -- `Build from source`_ - - * `Prerequisites`_ - - * `Create a build environment`_ - - * `C and C++ Libraries`_ - - * `Building the Googletests`_ - - * `Python Library`_ - - * `Rust Library`_ - - * `Using CMake Directly`_ - -- `Build Documentation`_ - - -Installing Pre-compiled Packages --------------------------------- - -**Note:** The cuVS pre-compiled packages are available for **Linux** only (x86_64 and aarch64 architectures). Native Windows support is not available at this time. On Windows, use **WSL2** with GPU passthrough. See the `RAPIDS WSL2 guide `_. - -C, C++, and Python through Conda -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The easiest way to install the pre-compiled C, C++, and Python packages is through conda. You can get a minimal conda installation with `miniforge `__. - -Use the following commands, depending on your CUDA version, to install cuVS packages (replace `rapidsai` with `rapidsai-nightly` to install more up-to-date but less stable nightly packages). `mamba` is preferred over the `conda` command and can be enabled using `this guide `_. - -C/C++ Package -~~~~~~~~~~~~~ - -.. code-block:: bash - - # CUDA 13 - conda install -c rapidsai -c conda-forge libcuvs cuda-version=13.2 - - # CUDA 12 - conda install -c rapidsai -c conda-forge libcuvs cuda-version=12.9 - -Python Package -~~~~~~~~~~~~~~ - -.. code-block:: bash - - # CUDA 13 - conda install -c rapidsai -c conda-forge cuvs cuda-version=13.2 - - # CUDA 12 - conda install -c rapidsai -c conda-forge cuvs cuda-version=12.9 - -Python through Pip -^^^^^^^^^^^^^^^^^^ - -The cuVS Python package can also be `installed through pip `_. - -.. code-block:: bash - - # CUDA 13 - pip install cuvs-cu13 --extra-index-url=https://pypi.nvidia.com - - # CUDA 12 - pip install cuvs-cu12 --extra-index-url=https://pypi.nvidia.com - -Note: these packages statically link the C and C++ libraries so the `libcuvs` and `libcuvs_c` shared libraries won't be readily available to use in your code. - -Tarball -^^^^^^^ - -Install Dependencies -~~~~~~~~~~~~~~~~~~~~ - -1. `NCCL `_ -2. `libopenmp` -3. CUDA Toolkit Runtime 12.2+ -4. Ampere architecture or better (compute capability >= 8.0) - -Download & Extract -~~~~~~~~~~~~~~~~~~ - -Download the pre-built tarball for your CPU architecture and CUDA version from -`https://developer.nvidia.com/cuvs-downloads `_ - -Untar the tarball into a directory. - -.. code-block:: bash - - tar -xzvf libcuvs-linux-sbsa-26.02.00.189485_cuda12-archive.tar.xz -C /path/to/folder - - -Add cuVS to your system library load path. This should be done in the appropriate profile configuration (for e.g. `.bashrc`, `.bash_profile`) to maintain the setting across sessions. - -.. code-block:: bash - - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/folder - - -Build from source ------------------ - -The core cuVS source code is written in C++ and wrapped through a C API. The C API is wrapped around the C++ APIs and the other supported languages are built around the C API. - -Prerequisites -^^^^^^^^^^^^^ - -- CMake 3.26.4+ -- GCC 9.3+ (11.4+ recommended) -- CUDA Toolkit 12.2+ -- Ampere architecture or better (compute capability >= 8.0) - -Create a build environment -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Conda environment scripts are provided for installing the necessary dependencies to build cuVS from source. It is preferred to use `mamba`, as it provides significant speedup over `conda`: - -.. code-block:: bash - - conda env create --name cuvs -f conda/environments/all_cuda-132_arch-$(uname -m).yaml - conda activate cuvs - -The recommended way to build and install cuVS from source is to use the `build.sh` script in the root of the repository. This script can build both the C++ and Python artifacts and provides CMake options for building and installing the headers, tests, benchmarks, and the pre-compiled shared library. - - -C and C++ libraries -^^^^^^^^^^^^^^^^^^^ - -The C and C++ shared libraries are built together using the following arguments to `build.sh`: - -.. code-block:: bash - - ./build.sh libcuvs - -In above example the `libcuvs.so` and `libcuvs_c.so` shared libraries are installed by default into `$INSTALL_PREFIX/lib`. To disable this, pass `-n` flag. - -Once installed, the shared libraries, headers (and any dependencies downloaded and installed via `rapids-cmake`) can be uninstalled using `build.sh`: - -.. code-block:: bash - - ./build.sh libcuvs --uninstall - - -Multi-GPU features -^^^^^^^^^^^^^^^^^^ - -To disable the multi-gpu features run : - -.. code-block:: bash - - ./build.sh libcuvs --no-mg - - -Building the Googletests -~~~~~~~~~~~~~~~~~~~~~~~~ - -Compile the C and C++ Googletests using the `tests` target in `build.sh`. - -.. code-block:: bash - - ./build.sh libcuvs tests - -The tests will be written to the build directory, which is `cpp/build/` by default, and they will be named `*_TEST`. - -It can take some time to compile all of the tests. You can build individual tests by providing a semicolon-separated list to the `--limit-tests` option in `build.sh`. Make sure to pass the `-n` flag so the tests are not installed. - -.. code-block:: bash - - ./build.sh libcuvs tests -n --limit-tests=NEIGHBORS_TEST;CAGRA_C_TEST - -Python library -^^^^^^^^^^^^^^ - -The Python library should be built and installed using the `build.sh` script: - -.. code-block:: bash - - ./build.sh python - -The Python packages can also be uninstalled using the `build.sh` script: - -.. code-block:: bash - - ./build.sh python --uninstall - -Go library -^^^^^^^^^^ - -After building the C and C++ libraries, the Golang library can be built with the following command: - -.. code-block:: bash - - export CUDA_HOME="/usr/local/cuda" # or wherever your CUDA installation is. - export CGO_CFLAGS="-I${CONDA_PREFIX}/include -I${CUDA_HOME}/include" - export CGO_LDFLAGS="-L${CONDA_PREFIX}/lib -lcuvs -lcuvs_c" - export LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" - export CC=clang - - ./build.sh go - -Rust library -^^^^^^^^^^^^ - -The Rust bindings can be built with - -.. code-block:: bash - - ./build.sh rust - -Using CMake directly -^^^^^^^^^^^^^^^^^^^^ - -When building cuVS from source, the `build.sh` script offers a nice wrapper around the `cmake` commands to ease the burdens of manually configuring the various available cmake options. When more fine-grained control over the CMake configuration is desired, the `cmake` command can be invoked directly as the below example demonstrates. - -The `CMAKE_INSTALL_PREFIX` installs cuVS into a specific location. The example below installs cuVS into the current Conda environment: - -.. code-block:: bash - - cd cpp - mkdir build - cd build - cmake -D BUILD_TESTS=ON -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX ../ - make -j install - -cuVS has the following configurable cmake flags available: - -.. list-table:: CMake Flags - - * - Flag - - Possible Values - - Default Value - - Behavior - - * - BUILD_TESTS - - ON, OFF - - ON - - Compile Googletests - - * - CUDA_ENABLE_KERNELINFO - - ON, OFF - - OFF - - Enables `kernelinfo` in nvcc. This is useful for `compute-sanitizer` - - * - CUDA_ENABLE_LINEINFO - - ON, OFF - - OFF - - Enable the `-lineinfo` option for nvcc - - * - CUDA_STATIC_MATH_LIBRARIES - - ON, OFF - - OFF - - Statically link the CUDA math libraries - - * - DETECT_CONDA_ENV - - ON, OFF - - ON - - Enable detection of conda environment for dependencies - - * - CUVS_NVTX - - ON, OFF - - OFF - - Enable NVTX markers - - -Build documentation -^^^^^^^^^^^^^^^^^^^ - -The documentation requires that the C, C++ and Python libraries have been built and installed. The following will build the docs along with the necessary libraries: - -.. code-block:: bash - - ./build.sh libcuvs python docs diff --git a/docs/source/c_api.rst b/docs/source/c_api.rst deleted file mode 100644 index c65eee06ef..0000000000 --- a/docs/source/c_api.rst +++ /dev/null @@ -1,14 +0,0 @@ -~~~~~~~~~~~~~~~~~~~ -C API Documentation -~~~~~~~~~~~~~~~~~~~ - -.. _api: - -.. toctree:: - :maxdepth: 4 - - c_api/core_c_api.rst - c_api/distance.rst - c_api/cluster.rst - c_api/neighbors.rst - c_api/preprocessing.rst diff --git a/docs/source/c_api/cluster.rst b/docs/source/c_api/cluster.rst deleted file mode 100644 index 34795e45bf..0000000000 --- a/docs/source/c_api/cluster.rst +++ /dev/null @@ -1,12 +0,0 @@ -Clustering -========== - -.. role:: py(code) - :language: c - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - cluster_kmeans_c.rst diff --git a/docs/source/c_api/cluster_kmeans_c.rst b/docs/source/c_api/cluster_kmeans_c.rst deleted file mode 100644 index b22003bc27..0000000000 --- a/docs/source/c_api/cluster_kmeans_c.rst +++ /dev/null @@ -1,27 +0,0 @@ -K-Means -======= - -.. role:: py(code) - :language: c - :class: highlight - -Parameters ----------- - -``#include `` - -.. doxygengroup:: kmeans_c_params - :project: cuvs - :members: - :content-only: - - -Functions ---------- - -``#include `` - -.. doxygengroup:: kmeans_c - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/core_c_api.rst b/docs/source/c_api/core_c_api.rst deleted file mode 100644 index e228394733..0000000000 --- a/docs/source/c_api/core_c_api.rst +++ /dev/null @@ -1,32 +0,0 @@ -Core Routines -============= - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Resources Handle ----------------- - -.. doxygengroup:: resources_c - :project: cuvs - :members: - :content-only: - -Error Handling --------------- - -.. doxygengroup:: error_c - :project: cuvs - :members: - :content-only: - -Logging -------- - -.. doxygengroup:: log_c - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/distance.rst b/docs/source/c_api/distance.rst deleted file mode 100644 index 8635ddf8bc..0000000000 --- a/docs/source/c_api/distance.rst +++ /dev/null @@ -1,26 +0,0 @@ -Distance -======== - -.. role:: py(code) - :language: c - :class: highlight - - -Distance types --------------- - -``#include `` - -.. doxygenenum:: cuvsDistanceType - :project: cuvs - - -Pairwise distance ------------------ - -``#include `` - -.. doxygengroup:: pairwise_distance_c - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors.rst b/docs/source/c_api/neighbors.rst deleted file mode 100644 index 305364bb2a..0000000000 --- a/docs/source/c_api/neighbors.rst +++ /dev/null @@ -1,19 +0,0 @@ -Nearest Neighbors -================= - -.. role:: py(code) - :language: c - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - neighbors_all_neighbors_c.rst - neighbors_bruteforce_c.rst - neighbors_cagra_c.rst - neighbors_hnsw_c.rst - neighbors_ivf_flat_c.rst - neighbors_ivf_pq_c.rst - neighbors_mg.rst - neighbors_vamana_c.rst diff --git a/docs/source/c_api/neighbors_all_neighbors_c.rst b/docs/source/c_api/neighbors_all_neighbors_c.rst deleted file mode 100644 index 7c6559979e..0000000000 --- a/docs/source/c_api/neighbors_all_neighbors_c.rst +++ /dev/null @@ -1,26 +0,0 @@ -All-Neighbors -============= - -The all-neighbors method constructs a k-NN graph for all vectors in a dataset. It supports multiple algorithms including brute force, IVF-PQ (approximate), and NN-Descent (approximate) for building local k-NN subgraphs. The API automatically detects whether the dataset is host-resident or device-resident and applies appropriate optimizations. - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Build parameters ----------------- - -.. doxygengroup:: all_neighbors_c_params - :project: cuvs - :members: - :content-only: - -Build ------ - -.. doxygengroup:: all_neighbors_c_build - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_bruteforce_c.rst b/docs/source/c_api/neighbors_bruteforce_c.rst deleted file mode 100644 index 36ba96f424..0000000000 --- a/docs/source/c_api/neighbors_bruteforce_c.rst +++ /dev/null @@ -1,42 +0,0 @@ -Bruteforce -========== - -The bruteforce method is running the KNN algorithm. It performs an extensive search, and in contrast to ANN methods produces an exact result. - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index ------ - -.. doxygengroup:: bruteforce_c_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: bruteforce_c_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: bruteforce_c_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: bruteforce_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_cagra_c.rst b/docs/source/c_api/neighbors_cagra_c.rst deleted file mode 100644 index 9d9f1b7ea9..0000000000 --- a/docs/source/c_api/neighbors_cagra_c.rst +++ /dev/null @@ -1,67 +0,0 @@ -CAGRA -===== - -CAGRA is a graph-based nearest neighbors algorithm that was built from the ground up for GPU acceleration. CAGRA demonstrates state-of-the art index build and query performance for both small- and large-batch sized search. - - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index build parameters ----------------------- - -.. doxygengroup:: cagra_c_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: cagra_c_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: cagra_c_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: cagra_c_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: cagra_c_index_search - :project: cuvs - :members: - :content-only: - -Index merge ------------ - -.. doxygengroup:: cagra_c_index_merge - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: cagra_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_hnsw_c.rst b/docs/source/c_api/neighbors_hnsw_c.rst deleted file mode 100644 index 3f10eea33b..0000000000 --- a/docs/source/c_api/neighbors_hnsw_c.rst +++ /dev/null @@ -1,65 +0,0 @@ -HNSW -==== - -This is a wrapper for hnswlib, to load a CAGRA index as an immutable HNSW index. The loaded HNSW index is only compatible in cuVS, and can be searched using wrapper functions. - - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index search parameters ------------------------ - -.. doxygengroup:: hnsw_c_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: hnsw_c_index - :project: cuvs - :members: - :content-only: - -Index extend parameters ------------------------ - -.. doxygengroup:: hnsw_c_extend_params - :project: cuvs - :members: - :content-only: - -Index extend ------------- -.. doxygengroup:: hnsw_c_index_extend - :project: cuvs - :members: - :content-only: - -Index load ----------- -.. doxygengroup:: hnsw_c_index_load - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: hnsw_c_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: hnsw_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_ivf_flat_c.rst b/docs/source/c_api/neighbors_ivf_flat_c.rst deleted file mode 100644 index a37b153bed..0000000000 --- a/docs/source/c_api/neighbors_ivf_flat_c.rst +++ /dev/null @@ -1,58 +0,0 @@ -IVF-Flat -======== - -The IVF-Flat method is an ANN algorithm. It uses an inverted file index (IVF) with unmodified (that is, flat) vectors. This algorithm provides simple knobs to reduce the overall search space and to trade-off accuracy for speed. - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index build parameters ----------------------- - -.. doxygengroup:: ivf_flat_c_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: ivf_flat_c_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: ivf_flat_c_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: ivf_flat_c_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: ivf_flat_c_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: ivf_flat_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_ivf_pq_c.rst b/docs/source/c_api/neighbors_ivf_pq_c.rst deleted file mode 100644 index ae985870b4..0000000000 --- a/docs/source/c_api/neighbors_ivf_pq_c.rst +++ /dev/null @@ -1,58 +0,0 @@ -IVF-PQ -====== - -The IVF-PQ method is an ANN algorithm. Like IVF-Flat, IVF-PQ splits the points into a number of clusters (also specified by a parameter called n_lists) and searches the closest clusters to compute the nearest neighbors (also specified by a parameter called n_probes), but it shrinks the sizes of the vectors using a technique called product quantization. - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index build parameters ----------------------- - -.. doxygengroup:: ivf_pq_c_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: ivf_pq_c_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: ivf_pq_c_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: ivf_pq_c_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: ivf_pq_c_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: ivf_pq_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_mg.rst b/docs/source/c_api/neighbors_mg.rst deleted file mode 100644 index bffe3fc4c5..0000000000 --- a/docs/source/c_api/neighbors_mg.rst +++ /dev/null @@ -1,257 +0,0 @@ -Multi-GPU Nearest Neighbors -=========================== - -The Multi-GPU (SNMG - single-node multi-GPUs) C API provides a set of functions to deploy ANN indexes across multiple GPUs for improved performance and scalability. - -.. role:: py(code) - :language: c - :class: highlight - -Common Types and Enums -====================== - -Common types and enums used across multi-GPU ANN algorithms. - -``#include `` - -.. doxygengroup:: mg_c_common_types - :project: cuvs - :members: - :content-only: - -Multi-GPU IVF-Flat -================== - -The Multi-GPU IVF-Flat method extends the IVF-Flat ANN algorithm to work across multiple GPUs. It provides two distribution modes: replicated (for higher throughput) and sharded (for handling larger datasets). - -``#include `` - -IVF-Flat Index Build Parameters -------------------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_params - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Search Parameters --------------------------------- - -.. doxygengroup:: mg_ivf_flat_c_search_params - :project: cuvs - :members: - :content-only: - -IVF-Flat Index --------------- - -.. doxygengroup:: mg_ivf_flat_c_index - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Build --------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_build - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Search ---------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_search - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Extend ---------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_extend - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Serialize ------------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_serialize - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Deserialize ---------------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_deserialize - :project: cuvs - :members: - :content-only: - -IVF-Flat Index Distribute --------------------------- - -.. doxygengroup:: mg_ivf_flat_c_index_distribute - :project: cuvs - :members: - :content-only: - -Multi-GPU IVF-PQ -================= - -The Multi-GPU IVF-PQ method extends the IVF-PQ ANN algorithm to work across multiple GPUs. It provides two distribution modes: replicated (for higher throughput) and sharded (for handling larger datasets). - -``#include `` - -IVF-PQ Index Build Parameters ------------------------------ - -.. doxygengroup:: mg_ivf_pq_c_index_params - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Search Parameters ------------------------------- - -.. doxygengroup:: mg_ivf_pq_c_search_params - :project: cuvs - :members: - :content-only: - -IVF-PQ Index ------------- - -.. doxygengroup:: mg_ivf_pq_c_index - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Build ------------------- - -.. doxygengroup:: mg_ivf_pq_c_index_build - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Search -------------------- - -.. doxygengroup:: mg_ivf_pq_c_index_search - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Extend -------------------- - -.. doxygengroup:: mg_ivf_pq_c_index_extend - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Serialize ----------------------- - -.. doxygengroup:: mg_ivf_pq_c_index_serialize - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Deserialize ------------------------- - -.. doxygengroup:: mg_ivf_pq_c_index_deserialize - :project: cuvs - :members: - :content-only: - -IVF-PQ Index Distribute ------------------------ - -.. doxygengroup:: mg_ivf_pq_c_index_distribute - :project: cuvs - :members: - :content-only: - -Multi-GPU CAGRA -================ - -The Multi-GPU CAGRA method extends the CAGRA graph-based ANN algorithm to work across multiple GPUs. It provides two distribution modes: replicated (for higher throughput) and sharded (for handling larger datasets). - -``#include `` - -CAGRA Index Build Parameters ----------------------------- - -.. doxygengroup:: mg_cagra_c_index_params - :project: cuvs - :members: - :content-only: - -CAGRA Index Search Parameters ------------------------------ - -.. doxygengroup:: mg_cagra_c_search_params - :project: cuvs - :members: - :content-only: - -CAGRA Index ------------ - -.. doxygengroup:: mg_cagra_c_index - :project: cuvs - :members: - :content-only: - -CAGRA Index Build ------------------ - -.. doxygengroup:: mg_cagra_c_index_build - :project: cuvs - :members: - :content-only: - -CAGRA Index Search ------------------- - -.. doxygengroup:: mg_cagra_c_index_search - :project: cuvs - :members: - :content-only: - -CAGRA Index Extend ------------------- - -.. doxygengroup:: mg_cagra_c_index_extend - :project: cuvs - :members: - :content-only: - -CAGRA Index Serialize ---------------------- - -.. doxygengroup:: mg_cagra_c_index_serialize - :project: cuvs - :members: - :content-only: - -CAGRA Index Deserialize ------------------------ - -.. doxygengroup:: mg_cagra_c_index_deserialize - :project: cuvs - :members: - :content-only: - -CAGRA Index Distribute ----------------------- - -.. doxygengroup:: mg_cagra_c_index_distribute - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/neighbors_vamana_c.rst b/docs/source/c_api/neighbors_vamana_c.rst deleted file mode 100644 index 90e47f1f6e..0000000000 --- a/docs/source/c_api/neighbors_vamana_c.rst +++ /dev/null @@ -1,43 +0,0 @@ -Vamana -====== - -Vamana is the graph construction algorithm behind the well-known DiskANN vector search solution. The cuVS implementation of Vamana/DiskANN is a custom GPU-acceleration version of the algorithm that aims to reduce index construction time using NVIDIA GPUs. - - -.. role:: py(code) - :language: c - :class: highlight - -``#include `` - -Index build parameters ----------------------- - -.. doxygengroup:: vamana_c_index_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: vamana_c_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: vamana_c_index_build - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: vamana_c_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/c_api/preprocessing.rst b/docs/source/c_api/preprocessing.rst deleted file mode 100644 index 1c65455de0..0000000000 --- a/docs/source/c_api/preprocessing.rst +++ /dev/null @@ -1,38 +0,0 @@ -Preprocessing -============= - -.. role:: py(code) - :language: c - :class: highlight - -Binary Quantizer ----------------- - -.. doxygengroup:: preprocessing_c_binary - :project: cuvs - :members: - :content-only: - -Product Quantizer ------------------ - -.. doxygengroup:: preprocessing_c_pq - :project: cuvs - :members: - :content-only: - -PCA (Principal Component Analysis) ------------------------------------ - -.. doxygengroup:: preprocessing_c_pca - :project: cuvs - :members: - :content-only: - -Scalar Quantizer ----------------- - -.. doxygengroup:: preprocessing_c_scalar - :project: cuvs - :members: - :content-only: diff --git a/docs/source/choosing_and_configuring_indexes.rst b/docs/source/choosing_and_configuring_indexes.rst deleted file mode 100644 index b4c140f295..0000000000 --- a/docs/source/choosing_and_configuring_indexes.rst +++ /dev/null @@ -1,98 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Primer on vector search indexes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Vector search indexes often use approximations to trade-off accuracy of the results for speed, either through lowering latency (end-to-end single query speed) or by increasing throughput (the number of query vectors that can be satisfied in a short period of time). Vector search indexes, especially ones that use approximations, are very closely related to machine learning models but they are optimized for fast search and accuracy of results. - -When the number of vectors is very small, such as less than 100 thousand vectors, it could be fast enough to use a brute-force (also known as a flat index), which returns exact results but at the expense of exhaustively searching all possible neighbors - -Objectives -========== - -This primer addresses the challenge of configuring vector search indexes, but its primary goal is to get a user up and running quickly with acceptable enough results for a good choice of index type and a small and manageable tuning knob, rather than providing a comprehensive guide to tuning each and every hyper-parameter. - -For this reason, we focus on 4 primary data sizes: - -#. Tiny datasets where GPU is likely not needed (< 100 thousand vectors) -#. Small datasets where GPU might not be needed (< 1 million vectors) -#. Large datasets (> 1 million vectors), goal is fast index creation at the expense of search quality -#. Large datasets where high quality is preferred at the expense of fast index creation - -Like other machine learning algorithms, vector search indexes generally have a training step – which means building the index – and an inference – or search step. The hyper-parameters also tend to be broken down into build and search parameters. - -While not always the case, a general trend is often observed where the search speed decreases as the quality increases. This also tends to be the case with the index build performance, though different algorithms have different relationships between build time, quality, and search time. It’s important to understand that there’s no free lunch so there will always be trade-offs for each index type. - -Definition of quality -===================== - -What do we mean when we say quality of an index? In machine learning terminology, we measure this using recall, which is sometimes used interchangeably to mean accuracy, even though the two are slightly different measures. Recall, when used in vector search, essentially means “out of all of my results, which results would have been included in the exact results?” In vector search, the objective is to find some number of vectors that are closest to a given query vector so recall tends to be more relaxed than accuracy, discriminating only on set inclusion, rather than on exact ordered list matching, which would be closer to an accuracy measure. - -Choosing vector search indexes -============================== - -Many vector search algorithms improve scalability while reducing the number of distances by partitioning the vector space into smaller pieces, often through the use of clustering, hashing, trees, and other techniques. Another popular technique is to reduce the width or dimensionality of the space in order to decrease the cost of computing each distance. - -Tiny datasets (< 100 thousand vectors) --------------------------------------- - -These datasets are very small and it’s questionable whether or not the GPU would provide any value at all. If the dimensionality is also relatively small (< 1024), you could just use brute-force or HNSW on the CPU and get great performance. If the dimensionality is relatively large (1536, 2048, 4096), you should consider using HNSW. If build time performance is critical, you should consider using CAGRA to build the graph and convert it to an HNSW graph for search (this capability exists today in the standalone cuVS/RAFT libraries and will soon be added to Milvus). An IVF flat index can also be a great candidate here, as it can improve the search performance over brute-force by partitioning the vector space and thus reducing the search space. - -Small datasets where GPU might not be needed (< 1 million vectors) ------------------------------------------------------------------- - -For smaller dimensionality, such as 1024 or below, you could consider using a brute-force (aka flat) index on GPU and get very good search performance with exact results. You could also use a graph-based index like HNSW on the CPU or CAGRA on the GPU. If build time is critical, you could even build a CAGRA graph on the GPU and convert it to HNSW graph on the CPU. - -For larger dimensionality (1536, 2048, 4096), you will start to see lower build-time performance with HNSW for higher quality search settings, and so it becomes more clear that building a CAGRA graph can be useful instead. - -Large datasets (> 1 million vectors), goal is fast index creation at the expense of search quality --------------------------------------------------------------------------------------------------- - -For fast ingest where slightly lower search quality is acceptable (85% recall and above), the IVF (inverted file index) methods can be very useful, as they can be very fast to build and still have acceptable search performance. IVF-flat index will partition the vectors into some number of clusters (specified by the user as n_lists) and at search time, some number of closest clusters (defined by n_probes) will be searched with brute-force for each query vector. - -IVF-PQ is similar to IVF-flat with the major difference that the vectors are compressed using a lossy product quantized compression so the index can have a much smaller footprint on the GPU. In general, it’s advised to set n_lists = sqrt(n_vectors) and set n_probes to some percentage of n_lists (e.g. 1%, 2%, 4%, 8%, 16%). Because IVF-PQ is a lossy compression, a refinement step can be performed by initially increasing the number of neighbors (by some multiple factor) and using the raw vectors to compute the exact distances, ultimately reducing the neighborhoods down to size k. Even a refinement of 2x (which would query initially for k*2) can be quite effective in making up for recall lost by the PQ compression, but it does come at the expense of having to keep the raw vectors around (keeping in mind many databases store the raw vectors anyways). - -Large datasets (> 1 million vectors), goal is high quality search at the expense of fast index creation -------------------------------------------------------------------------------------------------------- - -By trading off index creation performance, an extremely high quality search model can be built. Generally, all of the vector search index types have hyperparameters that have a direct correlation with the search accuracy and so they can be cranked up to yield better recall. Unfortunately, this can also significantly increase the index build time and reduce the search throughput. The trick here is to find the fastest build time that can achieve the best recall with the lowest latency or highest throughput possible. - -As for suggested index types, graph-based algorithms like HNSW and CAGRA tend to scale very well to larger datasets while having superior search performance with respect to quality. The challenge is that graph-based indexes require learning a graph and so, as the subtitle of this section suggests, have a tendency to be slower to build than other options. Using the CAGRA algorithm on the GPU can reduce the build time significantly over HNSW, while also having a superior throughput (and lower latency) than searching on the CPU. Currently, the downside to using CAGRA on the GPU is that it requires both the graph and the raw vectors to fit into GPU memory. A middle-ground can be reached by building a CAGRA graph on the GPU and converting it to an HNSW for high quality (and moderately fast) search on the CPU. - - -Tuning and hyperparameter optimization -====================================== - -Unfortunately, for large datasets, doing a hyper-parameter optimization on the whole dataset is not always feasible. It is possible, however, to perform a hyper-parameter optimization on the smaller subsets and find reasonably acceptable parameters that should generalize fairly well to the entire dataset. Generally this hyper-parameter optimization will require computing a ground truth on the subset with an exact method like brute-force and then using it to evaluate several searches on randomly sampled vectors. - -Full hyper-parameter optimization may also not always be necessary- for example, once you have built a ground truth dataset on a subset, many times you can start by building an index with the default build parameters and then playing around with different search parameters until you get the desired quality and search performance. For massive indexes that might be multiple terabytes, you could also take this subsampling of, say, 10M vectors, train an index and then tune the search parameters from there. While there might be a small margin of error, the chosen build/search parameters should generalize fairly well for the databases that build locally partitioned indexes. - - -Summary of vector search index types -==================================== - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Trade-offs - - Best to use with... - * - Brute-force (aka flat) - - Exact search but requires exhaustive distance computations - - Tiny datasets (< 100k vectors) - * - IVF-Flat - - Partitions the vector space to reduce distance computations for brute-force search at the expense of recall - - Small datasets (<1M vectors) or larger datasets (>1M vectors) where fast index build time is prioritized over quality. - * - IVF-PQ - - Adds product quantization to IVF-Flat to achieve scale at the expense of recall - - Large datasets (>>1M vectors) where fast index build is prioritized over quality - * - HNSW - - Significantly reduces distance computations at the expense of longer build times - - Small datasets (<1M vectors) or large datasets (>1M vectors) where quality and speed of search are prioritized over index build times - * - CAGRA - - Significantly reduces distance computations at the expense of longer build times (though build times improve over HNSW) - - Large datasets (>>1M vectors) where quality and speed of search are prioritized over index build times but index build times are still important. - * - CAGRA build +HNSW search - - (coming soon to Milvus) - - Significantly reduces distance computations and improves build times at the expense of higher search latency / lower throughput. - Large datasets (>>1M vectors) where index build times and quality of search is important but GPU resources are limited and latency of search is not. diff --git a/docs/source/comparing_indexes.rst b/docs/source/comparing_indexes.rst deleted file mode 100644 index 167aa2e072..0000000000 --- a/docs/source/comparing_indexes.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _comparing_indexes: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Comparing performance of vector indexes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This document provides a brief overview methodology for comparing vector search indexes and models. For guidance on how to choose and configure an index type, please refer to :doc:`this ` guide. - -Unlike traditional database indexes, which will generally return correct results even without performance tuning, vector search indexes are more closely related to ML models and they can return absolutely garbage results if they have not been tuned. - -For this reason, it’s important to consider the parameters that an index is built upon, both for its potential quality and throughput/latency, when comparing two trained indexes. While easier to build an index on its default parameters than having to tune them, a well tuned index can have a significantly better search quality AND perform within search perf constraints like maximal throughput and minimal latency. - - -What is recall? -=============== - -Recall is a measure of model quality. Imagine for a particular vector, we know the exact nearest neighbors because we computed them already. The recall for a query result can be computed by taking the set intersection between the exact nearest neighbors and the actual nearest neighbors. The number of neighbors in that intersection list gets divided by k, the number of neighbors being requested. To really give a fair estimate of the recall of a model, we use several query vectors, all with ground truth computed, and we take the total neighbors across all intersected neighbor lists and divide by n_queries * k. - -Parameter settings dictate the quality of an index. The graph below shows eight indexes from the same data but with different tuning parameters. Generally speaking, the indexes with higher average recall took longer to build. Which index is fair to report? - -.. image:: images/index_recalls.png - - -How do I compare models or indexing algorithms? -=============================================== - -In order to fairly compare the performance (e.g. latency and throughput) of an indexing algorithm or model against another, we always need to do so with respect to its potential recall. This is important and draws from the ML roots of vector search, but is often confusing to newcomers who might be more familiar with the database world. - -Best practice: Latency and throughput can only be compared at similar levels of recall. If you measure the performance of two indexes at different levels of recall, you are making an unfair comparison. - -Because recall levels can vary quite a bit across parameter settings, we tend to compare recall within a small set of potential buckets, so that parameter settings that perform within each bucket can be fairly compared. - -We suggest averaging performance within a range of recall. For general guidance, we tend to use the following buckets: - -#. 85% - 89% -#. 90% - 94% -#. 95% - 99% -#. >99% - -.. image:: images/recall_buckets.png - - -This allows us to make observations such as “at 95% recall level, model A can be built 3x faster than model B, but model B has 2x lower latency than model A” - -.. image:: images/build_benchmarks.png - - -Another important detail is that we compare these models against their best-case search performance within each recall window. This means that we aim to find models that not only have great recall quality but also have either the highest throughput or lowest latency within the window of interest. These best-cases are most often computed by doing a parameter sweep in a grid search (or other types of search optimizers) and looking at the best cases for each level of recall. - -The resulting data points will construct a curve known as a Pareto optimum. Please note that this process is specifically for showing best-case across recall and throughput/latency, but when we care about finding the parameters that yield the best recall and search performance, we are essentially performing a hyperparameter optimization, which is common in machine learning. - - -How do I do this on large vector databases? -=========================================== - -It turns out that most vector databases, like Milvus for example, make many smaller vector search indexing models for a single “index”, and the distribution of the vectors across the smaller index models are assumed to be completely uniform. This means we can use subsampling to our benefit, and tune on smaller sub-samples of the overall dataset. - -Please note, however, that there are often caps on the size of each of these smaller indexes, and that needs to be taken into consideration when choosing the size of the sub sample to tune. - -Please see :doc:`this guide ` for more information on the steps one would take to do this subsampling and tuning process. diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index ffec63ded9..0000000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,220 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2026, NVIDIA CORPORATION. -# SPDX-License-Identifier: Apache-2.0 - -import os -import sys -from packaging.version import Version - -import cuvs - -# If extensions (or modules to document with autodoc) are in another -# directory, add these directories to sys.path here. If the directory -# is relative to the documentation root, use os.path.abspath to make it -# absolute, like shown here. -sys.path.insert(0, os.path.abspath("sphinxext")) - -from github_link import make_linkcode_resolve # noqa - - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - "numpydoc", - "sphinx.ext.linkcode", - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.doctest", - "sphinx.ext.intersphinx", - "IPython.sphinxext.ipython_console_highlighting", - "IPython.sphinxext.ipython_directive", - "breathe", - "recommonmark", - "sphinx_markdown_tables", - "sphinx_copybutton", -] - -breathe_default_project = "cuvs" -breathe_projects = { - "cuvs": "../../cpp/doxygen/_xml/", -} -ipython_mplbackend = "str" - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# generate autosummary even if no references -# autosummary_generate = True - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = {".rst": "restructuredtext", ".md": "markdown"} - -# The master toctree document. -master_doc = "index" - -# General information about the project. -project = "cuvs" -copyright = "2024 - 2026, NVIDIA Corporation" -author = "NVIDIA Corporation" - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -CUVS_VERSION = Version(cuvs.__version__) -# The short X.Y version. -version = f"{CUVS_VERSION.major:02}.{CUVS_VERSION.minor:02}" -# The full version, including alpha/beta/rc tags. -release = ( - f"{CUVS_VERSION.major:02}.{CUVS_VERSION.minor:02}.{CUVS_VERSION.micro:02}" -) - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = "en" - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# - -html_theme = "nvidia_sphinx_theme" - - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -html_theme_options = { - "external_links": [], - # https://github.com/pydata/pydata-sphinx-theme/issues/1220 - "icon_links": [], - "github_url": "https://github.com/rapidsai/cuvs", - "twitter_url": "https://twitter.com/rapidsai", - "show_toc_level": 1, - "navbar_align": "right", -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -html_js_files = [] - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = "cuvsdoc" - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ( - master_doc, - "cuvs.tex", - "cuVS Documentation", - "NVIDIA Corporation", - "manual", - ), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "cuvs", "cuVS Documentation", [author], 1)] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ( - master_doc, - "cuvs", - "cuVS Documentation", - author, - "cuvs", - "One line description of project.", - "Miscellaneous", - ), -] - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - "python": ("https://docs.python.org/", None), - "scipy": ("https://docs.scipy.org/doc/scipy/", None), -} - -# Config numpydoc -numpydoc_show_inherited_class_members = False -numpydoc_class_members_toctree = False - - -def setup(app): - app.add_css_file("references.css") - app.add_css_file("https://docs.rapids.ai/assets/css/custom.css") - app.add_js_file( - "https://docs.rapids.ai/assets/js/custom.js", loading_method="defer" - ) - app.add_js_file("collapse_overloads.js") - - -# The following is used by sphinx.ext.linkcode to provide links to github -linkcode_resolve = make_linkcode_resolve( - "cuvs", - "https://github.com/rapidsai/cuvs/" - "blob/{revision}/python/cuvs/" - "{package}/{path}#L{lineno}", -) - -# Set the default role for interpreted code (anything surrounded in `single -# backticks`) to be a python object. See -# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-default_role -default_role = "py:obj" - -suppress_warnings = ["duplicate_declaration.cpp"] diff --git a/docs/source/cpp_api.rst b/docs/source/cpp_api.rst deleted file mode 100644 index 34f48a88f6..0000000000 --- a/docs/source/cpp_api.rst +++ /dev/null @@ -1,15 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~ -C++ API Documentation -~~~~~~~~~~~~~~~~~~~~~ - -.. _api: - -.. toctree:: - :maxdepth: 4 - - cpp_api/cluster.rst - cpp_api/distance.rst - cpp_api/neighbors.rst - cpp_api/preprocessing.rst - cpp_api/selection.rst - cpp_api/stats.rst diff --git a/docs/source/cpp_api/cluster.rst b/docs/source/cpp_api/cluster.rst deleted file mode 100644 index 8165a7d115..0000000000 --- a/docs/source/cpp_api/cluster.rst +++ /dev/null @@ -1,14 +0,0 @@ -Cluster -======= - -.. role:: py(code) - :language: c++ - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - cluster_agglomerative.rst - cluster_kmeans.rst - cluster_spectral.rst diff --git a/docs/source/cpp_api/cluster_agglomerative.rst b/docs/source/cpp_api/cluster_agglomerative.rst deleted file mode 100644 index 57a46504c4..0000000000 --- a/docs/source/cpp_api/cluster_agglomerative.rst +++ /dev/null @@ -1,31 +0,0 @@ -Agglomerative -============= - -.. role:: py(code) - :language: c++ - :class: highlight - -Parameters ----------- - -``#include `` - -namespace *cuvs::cluster::agglomerative* - -.. doxygengroup:: agglomerative_params - :project: cuvs - :members: - :content-only: - - -Agglomerative -------------- - -``#include `` - -namespace *cuvs::cluster::agglomerative* - -.. doxygengroup:: single_linkage - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/cluster_kmeans.rst b/docs/source/cpp_api/cluster_kmeans.rst deleted file mode 100644 index 70ab57bcbd..0000000000 --- a/docs/source/cpp_api/cluster_kmeans.rst +++ /dev/null @@ -1,44 +0,0 @@ -K-Means -======= - -.. role:: py(code) - :language: c++ - :class: highlight - -Parameters ----------- - -``#include `` - -namespace *cuvs::cluster::kmeans* - -.. doxygengroup:: kmeans_params - :project: cuvs - :members: - :content-only: - - -K-means -------- - -``#include `` - -namespace *cuvs::cluster::kmeans* - -.. doxygengroup:: kmeans - :project: cuvs - :members: - :content-only: - - -K-means Helpers ---------------- - -``#include `` - -namespace *cuvs::cluster::kmeans::helpers* - -.. doxygengroup:: kmeans_helpers - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/cluster_spectral.rst b/docs/source/cpp_api/cluster_spectral.rst deleted file mode 100644 index 19dedeef19..0000000000 --- a/docs/source/cpp_api/cluster_spectral.rst +++ /dev/null @@ -1,28 +0,0 @@ -Spectral Clustering -=================== - -Spectral clustering is a graph-based clustering technique that uses the eigenvalues of similarity matrices to identify clusters with complex, non-convex shapes. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::cluster::spectral* - -Parameters ----------- - -.. doxygengroup:: spectral_params - :project: cuvs - :members: - :content-only: - -Spectral Clustering -------------------- - -.. doxygengroup:: spectral - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/distance.rst b/docs/source/cpp_api/distance.rst deleted file mode 100644 index 994fbdaff5..0000000000 --- a/docs/source/cpp_api/distance.rst +++ /dev/null @@ -1,32 +0,0 @@ -Distance -======== - -This page provides C++ class references for the publicly-exposed elements of the `cuvs/distance` package. cuVS's -distances have been highly optimized and support a wide assortment of different distance measures. - -.. role:: py(code) - :language: c++ - :class: highlight - -Distance Types --------------- - -``#include `` - -namespace *cuvs::distance* - -.. doxygenenum:: cuvsDistanceType - :project: cuvs - - -Pairwise Distances ------------------- - -``#include `` - -namespace *cuvs::distance* - -.. doxygengroup:: pairwise_distance - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors.rst b/docs/source/cpp_api/neighbors.rst deleted file mode 100644 index 66b4e0c4aa..0000000000 --- a/docs/source/cpp_api/neighbors.rst +++ /dev/null @@ -1,24 +0,0 @@ -Nearest Neighbors -================= - -.. role:: py(code) - :language: c++ - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - neighbors_all_neighbors.rst - neighbors_bruteforce.rst - neighbors_cagra.rst - neighbors_dynamic_batching.rst - neighbors_epsilon_neighborhood.rst - neighbors_filter.rst - neighbors_hnsw.rst - neighbors_ivf_flat.rst - neighbors_ivf_pq.rst - neighbors_mg.rst - neighbors_nn_descent.rst - neighbors_refine.rst - neighbors_vamana.rst diff --git a/docs/source/cpp_api/neighbors_all_neighbors.rst b/docs/source/cpp_api/neighbors_all_neighbors.rst deleted file mode 100644 index 3a7eaee61f..0000000000 --- a/docs/source/cpp_api/neighbors_all_neighbors.rst +++ /dev/null @@ -1,29 +0,0 @@ -All-Neighbors -============= - -All-Neighbors allows building an approximate all-neighbors knn graph. Given a full dataset, it finds nearest neighbors for all the training vectors in the dataset. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::all_neighbors* - -Build Parameters ----------------- - -.. doxygengroup:: all_neighbors_cpp_params - :project: cuvs - :members: - :content-only: - - -Build ------ - -.. doxygengroup:: all_neighbors_cpp_build - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_bruteforce.rst b/docs/source/cpp_api/neighbors_bruteforce.rst deleted file mode 100644 index 1a3f2f7154..0000000000 --- a/docs/source/cpp_api/neighbors_bruteforce.rst +++ /dev/null @@ -1,44 +0,0 @@ -Bruteforce -========== - -The bruteforce method is running the KNN algorithm. It performs an extensive search, and in contrast to ANN methods produces an exact result. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::bruteforce* - -Index ------ - -.. doxygengroup:: bruteforce_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: bruteforce_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: bruteforce_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: bruteforce_cpp_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_cagra.rst b/docs/source/cpp_api/neighbors_cagra.rst deleted file mode 100644 index aa1e6ed117..0000000000 --- a/docs/source/cpp_api/neighbors_cagra.rst +++ /dev/null @@ -1,84 +0,0 @@ -CAGRA -===== - -CAGRA is a graph-based nearest neighbors algorithm that was built from the ground up for GPU acceleration. CAGRA demonstrates state-of-the art index build and query performance for both small- and large-batch sized search. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::cagra* - -Index build parameters ----------------------- - -.. doxygengroup:: cagra_cpp_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: cagra_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index extend parameters ------------------------ - -.. doxygengroup:: cagra_cpp_extend_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: cagra_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: cagra_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: cagra_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index extend ------------- - -.. doxygengroup:: cagra_cpp_index_extend - :project: cuvs - :members: - :content-only: - -Index merge ------------ - -.. doxygengroup:: cagra_cpp_index_merge - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: cagra_cpp_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_dynamic_batching.rst b/docs/source/cpp_api/neighbors_dynamic_batching.rst deleted file mode 100644 index adc5cb56aa..0000000000 --- a/docs/source/cpp_api/neighbors_dynamic_batching.rst +++ /dev/null @@ -1,45 +0,0 @@ -Dynamic Batching -================ - -Dynamic Batching allows grouping small search requests into batches to increase the device occupancy and throughput while keeping the latency within limits. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::dynamic_batching* - -Index build parameters ----------------------- - -.. doxygengroup:: dynamic_batching_cpp_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: dynamic_batching_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: dynamic_batching_cpp_index - :project: cuvs - :members: - :content-only: - - -Index search ------------- - -.. doxygengroup:: dynamic_batching_cpp_search - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_epsilon_neighborhood.rst b/docs/source/cpp_api/neighbors_epsilon_neighborhood.rst deleted file mode 100644 index 1ca957bfed..0000000000 --- a/docs/source/cpp_api/neighbors_epsilon_neighborhood.rst +++ /dev/null @@ -1,20 +0,0 @@ -Epsilon Neighborhood -==================== - -Epsilon neighborhood finds all neighbors within a given radius (epsilon) for each point in a dataset. Unlike k-nearest neighbors which finds a fixed number of neighbors, epsilon neighborhood finds all points within a specified distance threshold, making it particularly useful for density-based algorithms and graph construction. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::epsilon_neighborhood* - -L2-Squared Distance Operations ------------------------------- - -.. doxygengroup:: epsilon_neighborhood_cpp_l2 - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_filter.rst b/docs/source/cpp_api/neighbors_filter.rst deleted file mode 100644 index aba1d348fe..0000000000 --- a/docs/source/cpp_api/neighbors_filter.rst +++ /dev/null @@ -1,18 +0,0 @@ -Filtering -========== - -All nearest neighbors search methods support filtering. Filtering is a method to reduce the number -of candidates that are considered for the nearest neighbors search. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors* - -.. doxygengroup:: neighbors_filtering - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_hnsw.rst b/docs/source/cpp_api/neighbors_hnsw.rst deleted file mode 100644 index 00dd3a213c..0000000000 --- a/docs/source/cpp_api/neighbors_hnsw.rst +++ /dev/null @@ -1,67 +0,0 @@ -HNSW -==== - -This is a wrapper for hnswlib, to load a CAGRA index as an immutable HNSW index. The loaded HNSW index is only compatible in cuVS, and can be searched using wrapper functions. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::hnsw* - -Index search parameters ------------------------ - -.. doxygengroup:: hnsw_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: hnsw_cpp_index - :project: cuvs - :members: - :content-only: - -Index extend parameters ------------------------ - -.. doxygengroup:: hnsw_cpp_extend_params - :project: cuvs - :members: - :content-only: - -Index extend ------------- -.. doxygengroup:: hnsw_cpp_index_extend - :project: cuvs - :members: - :content-only: - -Index load ----------- - -.. doxygengroup:: hnsw_cpp_index_load - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: hnsw_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: hnsw_cpp_index_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_ivf_flat.rst b/docs/source/cpp_api/neighbors_ivf_flat.rst deleted file mode 100644 index 3836223e10..0000000000 --- a/docs/source/cpp_api/neighbors_ivf_flat.rst +++ /dev/null @@ -1,68 +0,0 @@ -IVF-Flat -======== - -The IVF-Flat method is an ANN algorithm. It uses an inverted file index (IVF) with unmodified (that is, flat) vectors. This algorithm provides simple knobs to reduce the overall search space and to trade-off accuracy for speed. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::ivf_flat* - -Index build parameters ----------------------- - -.. doxygengroup:: ivf_flat_cpp_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: ivf_flat_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: ivf_flat_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: ivf_flat_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index extend ------------- - -.. doxygengroup:: ivf_flat_cpp_index_extend - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: ivf_flat_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: ivf_flat_cpp_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_ivf_pq.rst b/docs/source/cpp_api/neighbors_ivf_pq.rst deleted file mode 100644 index cc515682b9..0000000000 --- a/docs/source/cpp_api/neighbors_ivf_pq.rst +++ /dev/null @@ -1,80 +0,0 @@ -IVF-PQ -====== - -The IVF-PQ method is an ANN algorithm. Like IVF-Flat, IVF-PQ splits the points into a number of clusters (also specified by a parameter called n_lists) and searches the closest clusters to compute the nearest neighbors (also specified by a parameter called n_probes), but it shrinks the sizes of the vectors using a technique called product quantization. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::ivf_pq* - -Index build parameters ----------------------- - -.. doxygengroup:: ivf_pq_cpp_index_params - :project: cuvs - :members: - :content-only: - -Index search parameters ------------------------ - -.. doxygengroup:: ivf_pq_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: ivf_pq_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: ivf_pq_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index extend ------------- - -.. doxygengroup:: ivf_pq_cpp_index_extend - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: ivf_pq_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: ivf_pq_cpp_serialize - :project: cuvs - :members: - :content-only: - -Helper Methods ---------------- - -Additional helper functions for manipulating the underlying data of an IVF-PQ index, unpacking records, and writing PQ codes into an existing IVF list. - -namespace *cuvs::neighbors::ivf_pq::helpers* - -.. doxygengroup:: ivf_pq_cpp_helpers - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_mg.rst b/docs/source/cpp_api/neighbors_mg.rst deleted file mode 100644 index a03490a157..0000000000 --- a/docs/source/cpp_api/neighbors_mg.rst +++ /dev/null @@ -1,76 +0,0 @@ -Multi-GPU Nearest Neighbors -=========================== - -The Multi-GPU (SNMG - single-node multi-GPUs) nearest neighbors API provides a set of functions to deploy ANN indexes across multiple GPUs for improved performance and scalability. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors* - -Index build parameters ----------------------- - -.. doxygengroup:: mg_cpp_index_params - :project: cuvs - :members: - :content-only: - -Search parameters ------------------ - -.. doxygengroup:: mg_cpp_search_params - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: mg_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index extend ------------- - -.. doxygengroup:: mg_cpp_index_extend - :project: cuvs - :members: - :content-only: - -Index search ------------- - -.. doxygengroup:: mg_cpp_index_search - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: mg_cpp_serialize - :project: cuvs - :members: - :content-only: - -Index deserialize ------------------ - -.. doxygengroup:: mg_cpp_deserialize - :project: cuvs - :members: - :content-only: - -Distribute pre-built local index --------------------------------- - -.. doxygengroup:: mg_cpp_distribute - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_nn_descent.rst b/docs/source/cpp_api/neighbors_nn_descent.rst deleted file mode 100644 index c21a1003db..0000000000 --- a/docs/source/cpp_api/neighbors_nn_descent.rst +++ /dev/null @@ -1,37 +0,0 @@ -NN-Descent -========== - -The NN-descent method is an ANN algorithm that directly approximates a k-nearest neighbors graph by randomly sampling points to compute distances and using neighbors of neighbors distances to reduce distance computations. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::nn_descent* - -Index build parameters ----------------------- - -.. doxygengroup:: nn_descent_cpp_index_params - :project: cuvs - :members: - :content-only: - - -Index ------ - -.. doxygengroup:: nn_descent_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: nn_descent_cpp_index_build - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_refine.rst b/docs/source/cpp_api/neighbors_refine.rst deleted file mode 100644 index 4a90ee9959..0000000000 --- a/docs/source/cpp_api/neighbors_refine.rst +++ /dev/null @@ -1,20 +0,0 @@ -Refinement -========== - -Candidate refinement methods for nearest neighbors search - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors* - -Index ------ - -.. doxygengroup:: ann_refine - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/neighbors_vamana.rst b/docs/source/cpp_api/neighbors_vamana.rst deleted file mode 100644 index 25447efce1..0000000000 --- a/docs/source/cpp_api/neighbors_vamana.rst +++ /dev/null @@ -1,44 +0,0 @@ -Vamana -====== - -Vamana is the graph construction algorithm behind the well-known DiskANN vector search solution. The cuVS implementation of Vamana/DiskANN is a custom GPU-acceleration version of the algorithm that aims to reduce index construction time using NVIDIA GPUs. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::neighbors::vamana* - -Index build parameters ----------------------- - -.. doxygengroup:: vamana_cpp_index_params - :project: cuvs - :members: - :content-only: - -Index ------ - -.. doxygengroup:: vamana_cpp_index - :project: cuvs - :members: - :content-only: - -Index build ------------ - -.. doxygengroup:: vamana_cpp_index_build - :project: cuvs - :members: - :content-only: - -Index serialize ---------------- - -.. doxygengroup:: vamana_cpp_serialize - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/preprocessing.rst b/docs/source/cpp_api/preprocessing.rst deleted file mode 100644 index 417c8faf7e..0000000000 --- a/docs/source/cpp_api/preprocessing.rst +++ /dev/null @@ -1,14 +0,0 @@ -Preprocessing -============= - -.. role:: py(code) - :language: c++ - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - preprocessing_pca.rst - preprocessing_quantize.rst - preprocessing_spectral_embedding.rst diff --git a/docs/source/cpp_api/preprocessing_pca.rst b/docs/source/cpp_api/preprocessing_pca.rst deleted file mode 100644 index 3083f42daf..0000000000 --- a/docs/source/cpp_api/preprocessing_pca.rst +++ /dev/null @@ -1,27 +0,0 @@ -PCA -=== - -Principal Component Analysis (PCA) is a linear dimensionality reduction technique that projects data onto orthogonal directions of maximum variance. - -.. role:: py(code) - :language: c++ - :class: highlight - -``#include `` - -namespace *cuvs::preprocessing::pca* - -Parameters ----------- - -.. doxygenstruct:: cuvs::preprocessing::pca::params - :project: cuvs - :members: - -PCA ---------- - -.. doxygengroup:: pca - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/preprocessing_quantize.rst b/docs/source/cpp_api/preprocessing_quantize.rst deleted file mode 100644 index fe8bf1ed8e..0000000000 --- a/docs/source/cpp_api/preprocessing_quantize.rst +++ /dev/null @@ -1,45 +0,0 @@ -Quantize -======== - -This page provides C++ class references for the publicly-exposed elements of the -`cuvs/preprocessing/quantize` package. - -.. role:: py(code) - :language: c++ - :class: highlight - -Binary Quantizer ----------------- - -``#include `` - -namespace *cuvs::preprocessing::quantize::binary* - -.. doxygengroup:: binary - :project: cuvs - :members: - :content-only: - -Product Quantizer ------------------ - -``#include `` - -namespace *cuvs::preprocessing::quantize::pq* - -.. doxygengroup:: pq - :project: cuvs - :members: - :content-only: - -Scalar Quantizer ----------------- - -``#include `` - -namespace *cuvs::preprocessing::quantize::scalar* - -.. doxygengroup:: scalar - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cpp_api/preprocessing_spectral_embedding.rst b/docs/source/cpp_api/preprocessing_spectral_embedding.rst deleted file mode 100644 index bfae68f9de..0000000000 --- a/docs/source/cpp_api/preprocessing_spectral_embedding.rst +++ /dev/null @@ -1,108 +0,0 @@ -Spectral Embedding -================== - -Spectral embedding is a powerful dimensionality reduction technique that uses the eigenvectors -of the graph Laplacian to embed high-dimensional data into a lower-dimensional space. This -method is particularly effective for discovering non-linear manifold structures in data and -is widely used in clustering, visualization, and feature extraction tasks. - -.. role:: py(code) - :language: c++ - :class: highlight - -Overview --------- - -The spectral embedding algorithm works by: - -1. **Graph Construction**: Building a k-nearest neighbors graph from the input data -2. **Laplacian Computation**: Computing the graph Laplacian matrix (normalized or unnormalized) -3. **Eigendecomposition**: Finding the eigenvectors corresponding to the smallest eigenvalues -4. **Embedding**: Using these eigenvectors as coordinates in the lower-dimensional space - -Parameters ----------- - -``#include `` - -namespace *cuvs::preprocessing::spectral_embedding* - -.. doxygenstruct:: cuvs::preprocessing::spectral_embedding::params - :project: cuvs - :members: - -Spectral Embedding ------------------- - -``#include `` - -namespace *cuvs::preprocessing::spectral_embedding* - -.. doxygengroup:: spectral_embedding - :project: cuvs - :content-only: - -Example Usage -------------- - -Basic Usage with Dataset -~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: cpp - - #include - #include - - // Initialize RAFT resources - raft::resources handle; - - // Configure spectral embedding parameters - cuvs::preprocessing::spectral_embedding::params params; - params.n_components = 2; // Reduce to 2D for visualization - params.n_neighbors = 15; // Local neighborhood size - params.norm_laplacian = true; // Use normalized Laplacian - params.drop_first = true; // Drop constant eigenvector - params.seed = 42; // For reproducibility - - // Create input dataset (n_samples x n_features) - int n_samples = 1000; - int n_features = 50; - auto dataset = raft::make_device_matrix(handle, n_samples, n_features); - // ... populate dataset with your data ... - - // Allocate output embedding matrix (n_samples x n_components) - auto embedding = raft::make_device_matrix( - handle, n_samples, params.n_components); - - // Perform spectral embedding - cuvs::preprocessing::spectral_embedding::transform( - handle, params, dataset.view(), embedding.view()); - -Using Precomputed Graph -~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: cpp - - #include - #include - - raft::resources handle; - - // Configure parameters (n_neighbors is ignored with precomputed graph) - cuvs::preprocessing::spectral_embedding::params params; - params.n_components = 3; - params.norm_laplacian = true; - params.drop_first = true; - params.seed = 42; - - // Assume we have a precomputed connectivity graph - // This could be from custom similarity computation or k-NN search - raft::device_coo_matrix connectivity_graph(...); - - // Allocate output embedding - auto embedding = raft::make_device_matrix( - handle, n_samples, params.n_components); - - // Perform spectral embedding with precomputed graph - cuvs::preprocessing::spectral_embedding::transform( - handle, params, connectivity_graph.view(), embedding.view()); diff --git a/docs/source/cpp_api/selection.rst b/docs/source/cpp_api/selection.rst deleted file mode 100644 index 5abe81662f..0000000000 --- a/docs/source/cpp_api/selection.rst +++ /dev/null @@ -1,19 +0,0 @@ -Selection -========= - -This page provides C++ class references for the publicly-exposed elements of the `cuvs/selection` -package. - -.. role:: py(code) - :language: c++ - :class: highlight - -Select-K --------- - -``#include `` - -namespace *cuvs::selection* - -.. doxygengroup:: select_k - :project: cuvs diff --git a/docs/source/cpp_api/stats.rst b/docs/source/cpp_api/stats.rst deleted file mode 100644 index 988ba05dfc..0000000000 --- a/docs/source/cpp_api/stats.rst +++ /dev/null @@ -1,34 +0,0 @@ -Stats -===== - - -This page provides C++ class references for the publicly-exposed elements of the `cuvs/stats` -package. - -.. role:: py(code) - :language: c++ - :class: highlight - -Silhouette Score ----------------- - -``#include `` - -namespace *cuvs::stats* - -.. doxygengroup:: stats_silhouette_score - :project: cuvs - :members: - :content-only: - -Trustworthiness Score ---------------------- - -``#include `` - -namespace *cuvs::stats* - -.. doxygengroup:: stats_trustworthiness - :project: cuvs - :members: - :content-only: diff --git a/docs/source/cuvs_bench/build.rst b/docs/source/cuvs_bench/build.rst deleted file mode 100644 index 1269cce45d..0000000000 --- a/docs/source/cuvs_bench/build.rst +++ /dev/null @@ -1,61 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Build cuVS Bench From Source -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Dependencies -============ - -CUDA 12 and a GPU with Volta architecture or later are required to run the benchmarks. - -Please refer to the :doc:`installation docs <../build>` for the base requirements to build cuVS. - -In addition to the base requirements for building cuVS, additional dependencies needed to build the ANN benchmarks include: - -1. FAISS GPU >= 1.7.1 -2. Google Logging (GLog) -3. H5Py -4. HNSWLib -5. nlohmann_json -6. GGNN - -`rapids-cmake `_ is used to build the ANN benchmarks so the code for dependencies not already supplied in the CUDA toolkit will be downloaded and built automatically. - -The easiest (and most reproducible) way to install the dependencies needed to build the ANN benchmarks is to use the conda environment file located in the `conda/environments` directory of the cuVS repository. The following command will use `mamba` (which is preferred over `conda`) to build and activate a new environment for compiling the benchmarks: - -.. code-block:: bash - - conda env create --name cuvs_benchmarks -f conda/environments/bench_ann_cuda-132_arch-$(uname -m).yaml - conda activate cuvs_benchmarks - -The above conda environment will also reduce the compile times as dependencies like FAISS will already be installed and not need to be compiled with `rapids-cmake`. - -Compiling the Benchmarks -======================== - -After the needed dependencies are satisfied, the easiest way to compile ANN benchmarks is through the `build.sh` script in the root of the RAFT source code repository. The following will build the executables for all the support algorithms: - -.. code-block:: bash - - ./build.sh bench-ann - -You can limit the algorithms that are built by providing a semicolon-delimited list of executable names (each algorithm is suffixed with `_ANN_BENCH`): - -.. code-block:: bash - - ./build.sh bench-ann -n --limit-bench-ann=HNSWLIB_ANN_BENCH;CUVS_IVF_PQ_ANN_BENCH - -Available targets to use with `--limit-bench-ann` are: - -- FAISS_GPU_IVF_FLAT_ANN_BENCH -- FAISS_GPU_IVF_PQ_ANN_BENCH -- FAISS_CPU_IVF_FLAT_ANN_BENCH -- FAISS_CPU_IVF_PQ_ANN_BENCH -- FAISS_GPU_FLAT_ANN_BENCH -- FAISS_CPU_FLAT_ANN_BENCH -- GGNN_ANN_BENCH -- HNSWLIB_ANN_BENCH -- CUVS_CAGRA_ANN_BENCH -- CUVS_IVF_PQ_ANN_BENCH -- CUVS_IVF_FLAT_ANN_BENCH - -By default, the `*_ANN_BENCH` executables program infer the dataset's datatype from the filename's extension. For example, an extension of `fbin` uses a `float` datatype, `f16bin` uses a `float16` datatype, extension of `i8bin` uses `int8_t` datatype, and `u8bin` uses `uint8_t` type. Currently, only `float`, `float16`, `int8_t`, and `unit8_t` are supported. diff --git a/docs/source/cuvs_bench/datasets.rst b/docs/source/cuvs_bench/datasets.rst deleted file mode 100644 index e6a53ca82b..0000000000 --- a/docs/source/cuvs_bench/datasets.rst +++ /dev/null @@ -1,62 +0,0 @@ -~~~~~~~~~~~~~~~~~~~ -cuVS Bench Datasets -~~~~~~~~~~~~~~~~~~~ - -A dataset usually has 4 binary files containing database vectors, query vectors, ground truth neighbors and their corresponding distances. For example, Glove-100 dataset has files `base.fbin` (database vectors), `query.fbin` (query vectors), `groundtruth.neighbors.ibin` (ground truth neighbors), and `groundtruth.distances.fbin` (ground truth distances). The first two files are for index building and searching, while the other two are associated with a particular distance and are used for evaluation. - -The file suffixes `.fbin`, `.f16bin`, `.ibin`, `.u8bin`, and `.i8bin` denote that the data type of vectors stored in the file are `float32`, `float16`(a.k.a `half`), `int`, `uint8`, and `int8`, respectively. -These binary files are little-endian and the format is: the first 8 bytes are `num_vectors` (`uint32_t`) and `num_dimensions` (`uint32_t`), and the following `num_vectors * num_dimensions * sizeof(type)` bytes are vectors stored in row-major order. - -Some implementation can take `float16` database and query vectors as inputs and will have better performance. Use `python/cuvs_bench/cuvs_bench/get_dataset/fbin_to_f16bin.py` to transform dataset from `float32` to `float16` type. - -Commonly used datasets can be downloaded from two websites: -#. Million-scale datasets can be found at the `Data sets `_ section of `ann-benchmarks `_. - - However, these datasets are in HDF5 format. Use `python/cuvs_bench/cuvs_bench/get_dataset/hdf5_to_fbin.py` to transform the format. The usage of this script is: - - .. code-block:: bash - - $ python/cuvs_bench/cuvs_bench/get_dataset/hdf5_to_fbin.py - usage: hdf5_to_fbin.py [-n] .hdf5 - -n: normalize base/query set - outputs: .base.fbin - .query.fbin - .groundtruth.neighbors.ibin - .groundtruth.distances.fbin - - So for an input `.hdf5` file, four output binary files will be produced. See previous section for an example of prepossessing GloVe dataset. - - Most datasets provided by `ann-benchmarks` use `Angular` or `Euclidean` distance. `Angular` denotes cosine distance. However, computing cosine distance reduces to computing inner product by normalizing vectors beforehand. In practice, we can always do the normalization to decrease computation cost, so it's better to measure the performance of inner product rather than cosine distance. The `-n` option of `hdf5_to_fbin.py` can be used to normalize the dataset. - -#. Billion-scale datasets can be found at `big-ann-benchmarks `_. The ground truth file contains both neighbors and distances, thus should be split. A script is provided for this: - - Take Deep-1B dataset as an example: - - .. code-block:: bash - - mkdir -p data/deep-1B && cd data/deep-1B - - # download manually "Ground Truth" file of "Yandex DEEP" - # suppose the file name is deep_new_groundtruth.public.10K.bin - python -m cuvs_bench.split_groundtruth deep_new_groundtruth.public.10K.bin groundtruth - - # two files 'groundtruth.neighbors.ibin' and 'groundtruth.distances.fbin' should be produced - - Besides ground truth files for the whole billion-scale datasets, this site also provides ground truth files for the first 10M or 100M vectors of the base sets. This mean we can use these billion-scale datasets as million-scale datasets. To facilitate this, an optional parameter `subset_size` for dataset can be used. See the next step for further explanation. - -Generate ground truth -===================== - -If you have a dataset, but no corresponding ground truth file, then you can generate ground trunth using the `generate_groundtruth` utility. Example usage: - -.. code-block:: bash - - # With existing query file - python -m cuvs_bench.generate_groundtruth --dataset /dataset/base.fbin --output=groundtruth_dir --queries=/dataset/query.public.10K.fbin - - # With randomly generated queries - python -m cuvs_bench.generate_groundtruth --dataset /dataset/base.fbin --output=groundtruth_dir --queries=random --n_queries=10000 - - # Using only a subset of the dataset. Define queries by randomly - # selecting vectors from the (subset of the) dataset. - python -m cuvs_bench.generate_groundtruth --dataset /dataset/base.fbin --nrows=2000000 --output=groundtruth_dir --queries=random-choice --n_queries=10000 diff --git a/docs/source/cuvs_bench/index.rst b/docs/source/cuvs_bench/index.rst deleted file mode 100644 index 928c988c1c..0000000000 --- a/docs/source/cuvs_bench/index.rst +++ /dev/null @@ -1,635 +0,0 @@ -~~~~~~~~~~ -cuVS Bench -~~~~~~~~~~ - -cuVS bench provides a reproducible benchmarking tool for various ANN search implementations. It's especially suitable for comparing GPU implementations as well as comparing GPU against CPU. One of the primary goals of cuVS is to capture ideal index configurations for a variety of important usage patterns so the results can be reproduced easily on different hardware environments, such as on-prem and cloud. - -This tool offers several benefits, including - -#. Making fair comparisons of index build times - -#. Making fair comparisons of index search throughput and/or latency - -#. Finding the optimal parameter settings for a range of recall buckets - -#. Easily generating consistently styled plots for index build and search - -#. Profiling blind spots and potential for algorithm optimization - -#. Investigating the relationship between different parameter settings, index build times, and search performance. - -- `Installing the benchmarks`_ - - * `Conda`_ - - * `Docker`_ - -- `Running the benchmarks`_ - - * `End-to-end: smaller-scale benchmarks (<1M to 10M)`_ - - * `End-to-end: large-scale benchmarks (>10M vectors)`_ - - * `Running with Docker containers`_ - - * `End-to-end run on GPU`_ - - * `Manually run the scripts inside the container`_ - - * `Evaluating the results`_ - -- `Creating and customizing dataset configurations`_ - - * `Multi-GPU benchmarks`_ - -- `Adding a new index algorithm`_ - - * `Implementation and configuration`_ - - * `Adding a Cmake target`_ - -Installing the benchmarks -========================= - -There are two main ways pre-compiled benchmarks are distributed: - -- `Conda`_ For users not using containers but want an easy to install and use Python package. Pip wheels are planned to be added as an alternative for users that cannot use conda and prefer to not use containers. -- `Docker`_ Only needs docker and `NVIDIA docker `_ to use. Provides a single docker run command for basic dataset benchmarking, as well as all the functionality of the conda solution inside the containers. - -Conda ------ - -.. code-block:: bash - - conda create --name cuvs_benchmarks - conda activate cuvs_benchmarks - - # to install GPU package: - conda install -c rapidsai -c conda-forge cuvs-bench= cuda-version=13.2* - - # to install CPU package for usage in CPU-only systems: - conda install -c rapidsai -c conda-forge cuvs-bench-cpu - -The channel `rapidsai` can easily be substituted with `rapidsai-nightly` if nightly benchmarks are desired. The CPU package currently allows to run the HNSW benchmarks. - -Please see the :doc:`build instructions ` to build the benchmarks from source. - -Docker ------- - -We provide images for GPU enabled systems, as well as systems without a GPU. The following images are available: - -- `cuvs-bench`: Contains GPU and CPU benchmarks, can run all algorithms supported. Will download million-scale datasets as required. Best suited for users that prefer a smaller container size for GPU based systems. Requires the NVIDIA Container Toolkit to run GPU algorithms, can run CPU algorithms without it. -- `cuvs-bench-cpu`: Contains only CPU benchmarks with minimal size. Best suited for users that want the smallest containers to reproduce benchmarks on systems without a GPU. - -Nightly images are located in `dockerhub `_. - -The following command pulls the nightly container for Python version 3.13, CUDA version 12.9, and cuVS version 26.06: - -.. code-block:: bash - - docker pull rapidsai/cuvs-bench:26.06a-cuda12-py3.13 # substitute cuvs-bench for the exact desired container. - -The CUDA and python versions can be changed for the supported values: -- Supported CUDA versions: 12, 13 -- Supported Python versions: 3.11, 3.11, 3.13, and 3.14 - -You can see the exact versions as well in the dockerhub site: -- `cuVS bench images `_ -- `cuVS bench CPU only images `_ - -**Note:** GPU containers use the CUDA toolkit from inside the container, the only requirement is a driver installed on the host machine that supports that version. So, for example, CUDA 12 containers can run in systems with a CUDA 13.x capable driver. Please also note that the Nvidia-Docker runtime from the `Nvidia Container Toolkit `_ is required to use GPUs inside docker containers. - -Running the benchmarks -====================== - -End-to-end: smaller-scale benchmarks (<1M to 10M) -------------------------------------------------- - -The steps below demonstrate how to download, install, and run benchmarks on a subset of 10M vectors from the Yandex Deep-1B dataset. By default the datasets will be stored and used from the folder indicated by the `RAPIDS_DATASET_ROOT_DIR` environment variable if defined, otherwise a datasets sub-folder from where the script is being called. - -.. code-block:: bash - - # (1) Prepare dataset. - python -m cuvs_bench.get_dataset --dataset deep-image-96-angular --normalize - - # (2) Build and search index. - python -m cuvs_bench.run --dataset deep-image-96-inner --algorithms cuvs_cagra --batch-size 10 -k 10 --build --search - - # (3) Export data. - python -m cuvs_bench.run --data-export --dataset deep-image-96-inner - - # (4) Plot results. - python -m cuvs_bench.plot --dataset deep-image-96-inner - -.. list-table:: - - * - Dataset name - - Train rows - - Columns - - Test rows - - Distance - - * - `deep-image-96-angular` - - 10M - - 96 - - 10K - - Angular - - * - `fashion-mnist-784-euclidean` - - 60K - - 784 - - 10K - - Euclidean - - * - `glove-50-angular` - - 1.1M - - 50 - - 10K - - Angular - - * - `glove-100-angular` - - 1.1M - - 100 - - 10K - - Angular - - * - `mnist-784-euclidean` - - 60K - - 784 - - 10K - - Euclidean - - * - `nytimes-256-angular` - - 290K - - 256 - - 10K - - Angular - - * - `sift-128-euclidean` - - 1M - - 128 - - 10K - - Euclidean - -All of the datasets above contain ground test datasets with 100 neighbors. Thus `k` for these datasets must be less than or equal to 100. - -End-to-end: large-scale benchmarks (>10M vectors) -------------------------------------------------- - -`cuvs_bench.get_dataset` cannot be used to download the billion-scale datasets due to their size. You should instead use our billion-scale datasets guide to download and prepare them. -All other python commands mentioned below work as intended once the billion-scale dataset has been downloaded. - -To download billion-scale datasets, visit `big-ann-benchmarks `_ - -We also provide a new dataset called `wiki-all` containing 88 million 768-dimensional vectors. This dataset is meant for benchmarking a realistic retrieval-augmented generation (RAG)/LLM embedding size at scale. It also contains 1M and 10M vector subsets for smaller-scale experiments. See our :doc:`Wiki-all Dataset Guide ` for more information and to download the dataset. - - -The steps below demonstrate how to download, install, and run benchmarks on a subset of 100M vectors from the Yandex Deep-1B dataset. Please note that datasets of this scale are recommended for GPUs with larger amounts of memory, such as the A100 or H100. - -.. code-block:: bash - - mkdir -p datasets/deep-1B - # (1) Prepare dataset. - # download manually "Ground Truth" file of "Yandex DEEP" - # suppose the file name is deep_new_groundtruth.public.10K.bin - python -m cuvs_bench.split_groundtruth --groundtruth datasets/deep-1B/deep_new_groundtruth.public.10K.bin - # two files 'groundtruth.neighbors.ibin' and 'groundtruth.distances.fbin' should be produced - -.. code-block:: bash - - # (2) Build and search index. - python -m cuvs_bench.run --dataset deep-1B --algorithms cuvs_cagra --batch-size 10 -k 10 --build --search - - # (3) Export data. - python -m cuvs_bench.run --data-export --dataset deep-1B - - # (4) Plot results. - python -m cuvs_bench.plot --dataset deep-1B - -The usage of `python -m cuvs_bench.split_groundtruth` is: - -.. code-block:: bash - - usage: split_groundtruth.py [-h] --groundtruth GROUNDTRUTH - - options: - -h, --help show this help message and exit - --groundtruth GROUNDTRUTH - Path to billion-scale dataset groundtruth file (default: None) - - -Testing on new datasets ------------------------ - -To run benchmark on a dataset, it is required have a descriptor that defines the file names and a few other properties of that dataset. -Descriptors for several popular datasets are already available in `datasets.yaml ``. - -Let's consider how to test on a new dataset. First we create a descriptor `mydataset.yaml` - -.. code-block: yaml - - name: mydata-1M - base_file: mydata-1M/base.100M.u8bin - subset_size: 1000000 - dims: 128 - query_file: mydata-10M/queries.u8bin - groundtruth_neighbors_file: mydata-1M/groundtruth.neighbors.ibin - distance: euclidean - -Here `name` can be chosen arbitrarily. We pass `name` as the `--dataset` argument for the benchmark. The file names are relative to the path given by `--dataset-path` argument. -The `subset_size`` field is optional. This argument defines how many vectors to use from the dataset file, the first `subset_size` vectors will be used. -This way you can define benchmarks on multiple subsets of the same dataset without duplicating the dataset vectors. -Note that the ground truth vectors have to be generated for each subset separately. - -To run the benchmark on the newly defined `mydata-1M` dataset, you can use the following command line: - -.. code-black: bash - python -m cuvs_bench.run --dataset mydata-1M --dataset-path=/path/to/data/folder --dataset-configuration=mydataset.yaml --algorithms=cuvs_cagra - -Running with Docker containers ------------------------------- - -Two methods are provided for running the benchmarks with the Docker containers. - -End-to-end run on GPU -~~~~~~~~~~~~~~~~~~~~~ - -When no other entrypoint is provided, an end-to-end script will run through all the steps in `Running the benchmarks`_ above. - -For GPU-enabled systems, the `DATA_FOLDER` variable should be a local folder where you want datasets stored in `$DATA_FOLDER/datasets` and results in `$DATA_FOLDER/result` (we highly recommend `$DATA_FOLDER` to be a dedicated folder for the datasets and results of the containers): - -.. code-block:: bash - - export DATA_FOLDER=path/to/store/datasets/and/results - docker run --gpus all --rm -it -u $(id -u) \ - -v $DATA_FOLDER:/data/benchmarks \ - rapidsai/cuvs-bench:26.06a-cuda12-py3.13 \ - "--dataset deep-image-96-angular" \ - "--normalize" \ - "--algorithms cuvs_cagra,cuvs_ivf_pq --batch-size 10 -k 10" \ - "" - -Usage of the above command is as follows: - -.. list-table:: - - * - Argument - - Description - - * - `rapidsai/cuvs-bench:26.06a-cuda12-py3.13` - - Image to use. See "Docker" section for links to lists of available tags. - - * - `"--dataset deep-image-96-angular"` - - Dataset name - - * - `"--normalize"` - - Whether to normalize the dataset - - * - `"--algorithms cuvs_cagra,hnswlib --batch-size 10 -k 10"` - - Arguments passed to the `run` script, such as the algorithms to benchmark, the batch size, and `k` - - * - `""` - - Additional (optional) arguments that will be passed to the `plot` script. - -***Note about user and file permissions:*** The flag `-u $(id -u)` allows the user inside the container to match the `uid` of the user outside the container, allowing the container to read and write to the mounted volume indicated by the `$DATA_FOLDER` variable. - -End-to-end run on CPU -~~~~~~~~~~~~~~~~~~~~~ - -The container arguments in the above section also be used for the CPU-only container, which can be used on systems that don't have a GPU installed. - -***Note:*** the image changes to `cuvs-bench-cpu` container and the `--gpus all` argument is no longer used: - -.. code-block:: bash - - export DATA_FOLDER=path/to/store/datasets/and/results - docker run --rm -it -u $(id -u) \ - -v $DATA_FOLDER:/data/benchmarks \ - rapidsai/cuvs-bench-cpu:26.06a-py3.13 \ - "--dataset deep-image-96-angular" \ - "--normalize" \ - "--algorithms hnswlib --batch-size 10 -k 10" \ - "" - -Manually run the scripts inside the container -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -All of the `cuvs-bench` images contain the Conda packages, so they can be used directly by logging directly into the container itself: - -.. code-block:: bash - - export DATA_FOLDER=path/to/store/datasets/and/results - docker run --gpus all --rm -it -u $(id -u) \ - --entrypoint /bin/bash \ - --workdir /data/benchmarks \ - -v $DATA_FOLDER:/data/benchmarks \ - rapidsai/cuvs-bench:26.06a-cuda12-py3.13 - -This will drop you into a command line in the container, with the `cuvs-bench` python package ready to use, as described in the `Running the benchmarks`_ section above: - -.. code-block:: bash - - (base) root@00b068fbb862:/data/benchmarks# python -m cuvs_bench.get_dataset --dataset deep-image-96-angular --normalize - -Additionally, the containers can be run in detached mode without any issue. - -Evaluating the results ----------------------- - -The benchmarks capture several different measurements. The table below describes each of the measurements for index build benchmarks: - -.. list-table:: - - * - Name - - Description - - * - Benchmark - - A name that uniquely identifies the benchmark instance - - * - Time - - Wall-time spent training the index - - * - CPU - - CPU time spent training the index - - * - Iterations - - Number of iterations (this is usually 1) - - * - GPU - - GU time spent building - - * - index_size - - Number of vectors used to train index - -The table below describes each of the measurements for the index search benchmarks. The most important measurements `Latency`, `items_per_second`, `end_to_end`. - -.. list-table:: - - * - Name - - Description - - * - Benchmark - - A name that uniquely identifies the benchmark instance - - * - Time - - The wall-clock time of a single iteration (batch) divided by the number of threads. - - * - CPU - - The average CPU time (user + sys time). This does not include idle time (which can also happen while waiting for GPU sync). - - * - Iterations - - Total number of batches. This is going to be `total_queries` / `n_queries`. - - * - GPU - - GPU latency of a single batch (seconds). In throughput mode this is averaged over multiple threads. - - * - Latency - - Latency of a single batch (seconds), calculated from wall-clock time. In throughput mode this is averaged over multiple threads. - - * - Recall - - Proportion of correct neighbors to ground truth neighbors. Note this column is only present if groundtruth file is specified in dataset configuration. - - * - items_per_second - - Total throughput, a.k.a Queries per second (QPS). This is approximately `total_queries` / `end_to_end`. - - * - k - - Number of neighbors being queried in each iteration - - * - end_to_end - - Total time taken to run all batches for all iterations - - * - n_queries - - Total number of query vectors in each batch - - * - total_queries - - Total number of vectors queries across all iterations ( = `iterations` * `n_queries`) - -Note the following: -- A slightly different method is used to measure `Time` and `end_to_end`. That is why `end_to_end` = `Time` * `Iterations` holds only approximately. -- The actual table displayed on the screen may differ slightly as the hyper-parameters will also be displayed for each different combination being benchmarked. -- Recall calculation: the number of queries processed per test depends on the number of iterations. Because of this, recall can show slight fluctuations if less neighbors are processed then it is available for the benchmark. - -Creating and customizing dataset configurations -=============================================== - -A single configuration will often define a set of algorithms, with associated index and search parameters, that can be generalize across datasets. We use YAML to define dataset specific and algorithm specific configurations. - -A default `datasets.yaml` is provided by CUVS in `${CUVS_HOME}/python/cuvs_bench/cuvs_bench/config/datasets/datasets.yaml` with configurations available for several datasets. Here's a simple example entry for the `sift-128-euclidean` dataset: - -.. code-block:: yaml - - - name: sift-128-euclidean - base_file: sift-128-euclidean/base.fbin - query_file: sift-128-euclidean/query.fbin - groundtruth_neighbors_file: sift-128-euclidean/groundtruth.neighbors.ibin - dims: 128 - distance: euclidean - -Configuration files for ANN algorithms supported by `cuvs-bench` are provided in `${CUVS_HOME}/python/cuvs_bench/cuvs_bench/config/algos`. `cuvs_cagra` algorithm configuration looks like: - -.. code-block:: yaml - - name: cuvs_cagra - constraints: - build: cuvs_bench.config.algos.constraints.cuvs_cagra_build - search: cuvs_bench.config.algos.constraints.cuvs_cagra_search - groups: - base: - build: - graph_degree: [32, 64] - intermediate_graph_degree: [64, 96] - graph_build_algo: ["NN_DESCENT"] - search: - itopk: [32, 64, 128] - - large: - build: - graph_degree: [32, 64] - search: - itopk: [32, 64, 128] - -The default parameters for which the benchmarks are run can be overridden by creating a custom YAML file for algorithms with a `base` group. - -The config above has 3 fields: - -1. `name` - The name of the algorithm for which the parameters are being specified. -2. `constraints` - Optional. Python import paths to functions that validate build and search parameter combinations (e.g. ``cuvs_bench.config.algos.constraints.cuvs_cagra_build``). Each function returns ``True`` if the parameters are valid, ``False`` otherwise; invalid combinations are skipped and not benchmarked. -3. `groups` - Run groups, each with a set of parameters. Each group defines a cross-product of all hyper-parameter fields for `build` and `search`. - -The table below contains all algorithms supported by cuVS. Each unique algorithm will have its own set of `build` and `search` settings. The :doc:`ANN Algorithm Parameter Tuning Guide ` contains detailed instructions on choosing build and search parameters for each supported algorithm. - -.. list-table:: - - * - Library - - Algorithms - - * - FAISS_GPU - - `faiss_gpu_flat`, `faiss_gpu_ivf_flat`, `faiss_gpu_ivf_pq`, `faiss_gpu_cagra` - - * - FAISS_CPU - - `faiss_cpu_flat`, `faiss_cpu_ivf_flat`, `faiss_cpu_ivf_pq`, `faiss_cpu_hnsw_flat` - - * - GGNN - - `ggnn` - - * - HNSWLIB - - `hnswlib` - - * - DiskANN - - `diskann_memory`, `diskann_ssd` - - * - cuVS - - `cuvs_brute_force`, `cuvs_cagra`, `cuvs_ivf_flat`, `cuvs_ivf_pq`, `cuvs_cagra_hnswlib`, `cuvs_vamana` - - -Multi-GPU benchmarks --------------------- - -cuVS implements single node multi-GPU versions of IVF-Flat, IVF-PQ and CAGRA indexes. - -.. list-table:: - - * - Index type - - Multi-GPU algo name - - * - IVF-Flat - - `cuvs_mg_ivf_flat` - - * - IVF-PQ - - `cuvs_mg_ivf_pq` - - * - CAGRA - - `cuvs_mg_cagra` - - -Adding a new index algorithm -============================ - -Implementation and configuration --------------------------------- - -Implementation of a new algorithm should be a C++ class that inherits `class ANN` (defined in `cpp/bench/ann/src/ann.h`) and implements all the pure virtual functions. - -In addition, it should define two `struct`s for building and searching parameters. The searching parameter class should inherit `struct ANN::AnnSearchParam`. Take `class HnswLib` as an example, its definition is: - -.. code-block:: c++ - - template - class HnswLib : public ANN { - public: - struct BuildParam { - int M; - int ef_construction; - int num_threads; - }; - - using typename ANN::AnnSearchParam; - struct SearchParam : public AnnSearchParam { - int ef; - int num_threads; - }; - - // ... - }; - - -The benchmark program uses JSON format natively in a configuration file to specify indexes to build, along with the build and search parameters. However the JSON config files are overly verbose and are not meant to be used directly. Instead, the Python scripts parse YAML and create these json files automatically. It's important to realize that these json objects align with the yaml objects for `build_param`, whose value is a JSON object, and `search_param`, whose value is an array of JSON objects. Take the json configuration for `HnswLib` as an example of the json after it's been parsed from yaml: - -.. code-block:: json - - { - "name" : "hnswlib.M12.ef500.th32", - "algo" : "hnswlib", - "build_param": {"M":12, "efConstruction":500, "numThreads":32}, - "file" : "/path/to/file", - "search_params" : [ - {"ef":10, "numThreads":1}, - {"ef":20, "numThreads":1}, - {"ef":40, "numThreads":1}, - ], - "search_result_file" : "/path/to/file" - }, - -The build and search params are ultimately passed to the C++ layer as json objects for each param configuration to benchmark. The code below shows how to parse these params for `Hnswlib`: - -1. First, add two functions for parsing JSON object to `struct BuildParam` and `struct SearchParam`, respectively: - -.. code-block:: c++ - - template - void parse_build_param(const nlohmann::json& conf, - typename cuann::HnswLib::BuildParam& param) { - param.ef_construction = conf.at("efConstruction"); - param.M = conf.at("M"); - if (conf.contains("numThreads")) { - param.num_threads = conf.at("numThreads"); - } - } - - template - void parse_search_param(const nlohmann::json& conf, - typename cuann::HnswLib::SearchParam& param) { - param.ef = conf.at("ef"); - if (conf.contains("numThreads")) { - param.num_threads = conf.at("numThreads"); - } - } - - - -2. Next, add corresponding `if` case to functions `create_algo()` (in `cpp/bench/ann/) and `create_search_param()` by calling parsing functions. The string literal in `if` condition statement must be the same as the value of `algo` in configuration file. For example, - -.. code-block:: c++ - - // JSON configuration file contains a line like: "algo" : "hnswlib" - if (algo == "hnswlib") { - // ... - } - -Adding a Cmake target ---------------------- - -In `cuvs/cpp/bench/ann/CMakeLists.txt`, we provide a `CMake` function to configure a new Benchmark target with the following signature: - - -.. code-block:: cmake - - ConfigureAnnBench( - NAME - PATH - INCLUDES - CXXFLAGS - LINKS - ) - -To add a target for `HNSWLIB`, we would call the function as: - -.. code-block:: cmake - - ConfigureAnnBench( - NAME HNSWLIB PATH bench/ann/src/hnswlib/hnswlib_benchmark.cpp INCLUDES - ${CMAKE_CURRENT_BINARY_DIR}/_deps/hnswlib-src/hnswlib CXXFLAGS "${HNSW_CXX_FLAGS}" - ) - -This will create an executable called `HNSWLIB_ANN_BENCH`, which can then be used to run `HNSWLIB` benchmarks. - -Add a new entry to `algos.yaml` to map the name of the algorithm to its binary executable and specify whether the algorithm requires GPU support. - -.. code-block:: yaml - - cuvs_ivf_pq: - executable: CUVS_IVF_PQ_ANN_BENCH - requires_gpu: true - -`executable` : specifies the name of the binary that will build/search the index. It is assumed to be available in `cuvs/cpp/build/`. -`requires_gpu` : denotes whether an algorithm requires GPU to run. - - -.. toctree:: - :maxdepth: 4 - - build.rst - datasets.rst - param_tuning.rst - pluggable_backend.rst - wiki_all_dataset.rst diff --git a/docs/source/cuvs_bench/param_tuning.rst b/docs/source/cuvs_bench/param_tuning.rst deleted file mode 100644 index 692fd7eb6a..0000000000 --- a/docs/source/cuvs_bench/param_tuning.rst +++ /dev/null @@ -1,918 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -cuVS Bench Parameter Tuning Guide -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This guide outlines the various parameter settings that can be specified in :doc:`cuVS Benchmarks ` yaml configuration files and explains the impact they have on corresponding algorithms to help inform their settings for benchmarking across desired levels of recall. - -Benchmark modes -=============== - -When you run benchmarks with ``BenchmarkOrchestrator.run_benchmark()``, you can choose how parameters are explored: - -**Sweep mode (default)** - -Pass ``mode="sweep"`` or omit ``mode``. The orchestrator builds the full Cartesian product of all build and search parameter lists defined in the algorithm YAML (see :doc:`Creating and customizing dataset configurations `). Every valid combination (after constraint filtering) is run. Use this for exhaustive comparison across the configured parameter grid. - -**Tune mode** - -Pass ``mode="tune"`` to perform hyperparameter optimization using Optuna instead of running every combination. You must pass: - -- **constraints** (dict): The optimization target and optional bounds. One metric must be ``"maximize"`` or ``"minimize"`` (the goal). Others can set hard limits with ``{"min": X}`` or ``{"max": X}``. Examples: ``{"recall": "maximize", "latency": {"max": 10}}`` or ``{"latency": "minimize", "recall": {"min": 0.95}}``. -- **n_trials** (int, optional): Maximum number of Optuna trials (default 100). Ignored in sweep mode. - -Example: - -.. code-block:: python - - results = orchestrator.run_benchmark( - mode="tune", - dataset="deep-image-96-inner", - algorithms="cuvs_cagra", - constraints={"recall": "maximize", "latency": {"max": 5.0}}, - n_trials=50, - count=10, - batch_size=10, - ) - -The parameter tables below describe the build and search knobs that sweep mode varies and that tune mode can optimize. - -cuVS Indexes -============ - -cuvs_brute_force ----------------- - -Use cuVS brute-force index for exact search. Brute-force has no further build or search parameters. - -cuvs_ivf_flat -------------- - -IVF-flat uses an inverted-file index, which partitions the vectors into a series of clusters, or lists, storing them in an interleaved format which is optimized for fast distance computation. The searching of an IVF-flat index reduces the total vectors in the index to those within some user-specified nearest clusters called probes. - -IVF-flat is a simple algorithm which won't save any space, but it provides competitive search times even at higher levels of recall. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlist` - - `build` - - Y - - Positive integer >0 - - 1024 - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained. - - * - `niter` - - `build` - - N - - Positive integer >0 - - 20 - - Number of kmeans iterations to use when training the ivf clusters - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `dataset_memory_type` - - `build` - - N - - [`device`, `host`, `mmap`] - - `mmap` - - Where should the dataset reside? - - * - `query_memory_type` - - `search` - - N - - [`device`, `host`, `mmap`] - - `device` - - Where should the queries reside? - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - -cuvs_ivf_pq ------------ - -IVF-pq is an inverted-file index, which partitions the vectors into a series of clusters, or lists, in a similar way to IVF-flat above. The difference is that IVF-PQ uses product quantization to also compress the vectors, giving the index a smaller memory footprint. Unfortunately, higher levels of compression can also shrink recall, which a refinement step can improve when the original vectors are still available. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlist` - - `build` - - Y - - Positive integer >0 - - 1024 - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained. - - * - `niter` - - `build` - - N - - Positive integer >0 - - 20 - - Number of kmeans iterations to use when training the ivf clusters - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `pq_dim` - - `build` - - N - - Positive integer. Multiple of 8. - - 0 - - Dimensionality of the vector after product quantization. When 0, a heuristic is used to select this value. - - * - `pq_bits` - - `build` - - N - - Positive integer [4-8] - - 8 - - Bit length of the vector element after quantization. - - * - `codebook_kind` - - `build` - - N - - [`cluster`, `subspace`] - - `subspace` - - Type of codebook. See :doc:`IVF-PQ index overview <../neighbors/ivfpq>` for more detail - - * - `dataset_memory_type` - - `build` - - N - - [`device`, `host`, `mmap`] - - `mmap` - - Where should the dataset reside? - - * - `query_memory_type` - - `search` - - N - - [`device`, `host`, `mmap`] - - `device` - - Where should the queries reside? - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - 20 - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - * - `internalDistanceDtype` - - `search` - - N - - [`float`, `half`] - - `half` - - The precision to use for the distance computations. Lower precision can increase performance at the cost of accuracy. - - * - `smemLutDtype` - - `search` - - N - - [`float`, `half`, `fp8`] - - `half` - - The precision to use for the lookup table in shared memory. Lower precision can increase performance at the cost of accuracy. - - * - `refine_ratio` - - `search` - - N - - Positive integer >0 - - 1 - - `refine_ratio * k` nearest neighbors are queried from the index initially and an additional refinement step improves recall by selecting only the best `k` neighbors. - - -cuvs_cagra ----------- - -CAGRA uses a graph-based index, which creates an intermediate, approximate kNN graph using IVF-PQ and then further refining and optimizing to create a final kNN graph. This kNN graph is used by CAGRA as an index for search. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `graph_degree` - - `build` - - N - - Positive integer >0 - - 64 - - Degree of the final kNN graph index. - - * - `intermediate_graph_degree` - - `build` - - N - - Positive integer >0 - - 128 - - Degree of the intermediate kNN graph before the CAGRA graph is optimized - - * - `graph_build_algo` - - `build` - - `N` - - [`IVF_PQ`, `NN_DESCENT`, `ACE`] - - `IVF_PQ` - - Algorithm to use for building the initial kNN graph, from which CAGRA will optimize into the navigable CAGRA graph - - * - `dataset_memory_type` - - `build` - - N - - [`device`, `host`, `mmap`] - - `mmap` - - Where should the dataset reside? - - * - `npartitions` - - `build` - - N - - Positive integer >0 - - 1 - - The number of partitions to use for the ACE build. Small values might improve recall but potentially degrade performance and increase memory usage. Partitions should not be too small to prevent issues in KNN graph construction. The partition size is on average 2 * (n_rows / npartitions) * dim * sizeof(T). 2 is because of the core and augmented vectors. Please account for imbalance in the partition sizes (up to 3x in our tests). - - * - `build_dir` - - `build` - - N - - String - - "/tmp/ace_build" - - The directory to use for the ACE build. Must be specified when using ACE build. This should be the fastest disk in the system and hold enough space for twice the dataset, final graph, and label mapping. - - * - `ef_construction` - - `build` - - Y - - Positive integer >0 - - 120 - - Controls index time and accuracy when using ACE build. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. - - * - `use_disk` - - `build` - - N - - Boolean - - `false` - - Whether to use disk-based storage for ACE build. When true, forces ACE to use disk-based storage even if the graph fits in host and GPU memory. When false, ACE will use in-memory storage if the graph fits in host and GPU memory and disk-based storage otherwise. - - * - `query_memory_type` - - `search` - - N - - [`device`, `host`, `mmap`] - - `device` - - Where should the queries reside? - - * - `itopk` - - `search` - - N - - Positive integer >0 - - 64 - - Number of intermediate search results retained during the search. Higher values improve search accuracy at the cost of speed - - * - `search_width` - - `search` - - N - - Positive integer >0 - - 1 - - Number of graph nodes to select as the starting point for the search in each iteration. - - * - `max_iterations` - - `search` - - N - - Positive integer >=0 - - 0 - - Upper limit of search iterations. Auto select when 0 - - * - `algo` - - `search` - - N - - [`auto`, `single_cta`, `multi_cta`, `multi_kernel`] - - `auto` - - Algorithm to use for search. It's usually best to leave this to `auto`. - - * - `graph_memory_type` - - `search` - - N - - [`device`, `host_pinned`, `host_huge_page`] - - `device` - - Memory type to store graph - - * - `internal_dataset_memory_type` - - `search` - - N - - [`device`, `host_pinned`, `host_huge_page`] - - `device` - - Memory type to store dataset - -The `graph_memory_type` or `internal_dataset_memory_type` options can be useful for large datasets that do not fit the device memory. Setting `internal_dataset_memory_type` other than `device` has negative impact on search speed. Using `host_huge_page` option is only supported on systems with Heterogeneous Memory Management or on platforms that natively support GPU access to system allocated memory, for example Grace Hopper. - -To fine tune CAGRA index building we can customize IVF-PQ index builder options using the following settings. These take effect only if `graph_build_algo == "IVF_PQ"`. It is recommended to experiment using a separate IVF-PQ index to find the config that gives the largest QPS for large batch. Recall does not need to be very high, since CAGRA further optimizes the kNN neighbor graph. Some of the default values are derived from the dataset size which is assumed to be [n_vecs, dim]. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `ivf_pq_build_nlist` - - `build` - - N - - Positive integer >0 - - sqrt(n_vecs) - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained. - - * - `ivf_pq_build_niter` - - `build` - - N - - Positive integer >0 - - 25 - - Number of k-means iterations to use when training the clusters. - - * - `ivf_pq_build_ratio` - - `build` - - N - - Positive integer >0 - - 10 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `ivf_pq_pq_dim` - - `build` - - N - - Positive integer. Multiple of 8 - - dim/2 rounded up to 8 - - Dimensionality of the vector after product quantization. When 0, a heuristic is used to select this value. `pq_dim` * `pq_bits` must be a multiple of 8. - - * - `ivf_pq_build_pq_bits` - - `build` - - N - - Positive integer [4-8] - - 8 - - Bit length of the vector element after quantization. - - * - `ivf_pq_build_codebook_kind` - - `build` - - N - - [`cluster`, `subspace`] - - `subspace` - - Type of codebook. See :doc:`IVF-PQ index overview <../neighbors/ivfpq>` for more detail - - * - `ivf_pq_build_nprobe` - - `search` - - N - - Positive integer >0 - - min(2*dim, nlist) - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - * - `ivf_pq_build_internalDistanceDtype` - - `search` - - N - - [`float`, `half`] - - `half` - - The precision to use for the distance computations. Lower precision can increase performance at the cost of accuracy. - - * - `ivf_pq_build_smemLutDtype` - - `search` - - N - - [`float`, `half`, `fp8`] - - `fp8` - - The precision to use for the lookup table in shared memory. Lower precision can increase performance at the cost of accuracy. - - * - `ivf_pq_build_refine_ratio` - - `search` - - N - - Positive integer >0 - - 2 - - `refine_ratio * k` nearest neighbors are queried from the index initially and an additional refinement step improves recall by selecting only the best `k` neighbors. - -Alternatively, if `graph_build_algo == "NN_DESCENT"`, then we can customize the following parameters - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nn_descent_niter` - - `build` - - N - - Positive integer >0 - - 20 - - Number of nn-descent iterations - - * - `nn_descent_intermediate_graph_degree` - - `build` - - N - - Positive integer >0 - - `cagra.intermediate_graph_degree` * 1.5 - - Intermadiate graph degree during nn-descent iterations - - * - nn_descent_termination_threshold - - `build` - - N - - Positive float >0 - - 1e-4 - - Early stopping threshold for nn-descent convergence - -cuvs_cagra_hnswlib ------------------- - -This is a benchmark that enables interoperability between `CAGRA` built `HNSW` search. It uses the `CAGRA` built graph as the base layer of an `hnswlib` index to search queries only within the base layer (this is enabled with a simple patch to `hnswlib`). - -`build` : Same as `build` of CAGRA - -`search` : Same as `search` of Hnswlib - -cuvs_vamana ------------ - -Benchmark for building an in-memory Vamana graph based index on the GPU and interoperability with DiskANN for search. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `graph_degree` - - `build` - - N - - Positive integer >0 - - 32 - - Maximum degree of the graph index - - * - `visited_size` - - `build` - - N - - Positive integer >0 - - 64 - - Maximum number of visited nodes per search corresponds to the L parameter in the Vamana literature - - * - `alpha` - - `build` - - N - - Positive float >0 - - 1.2 - - Alpha for pruning parameter - - * - `L_search` - - `search` - - Y - - Positive integer >0 - - - - Maximum number of visited nodes per search corresponds to the L parameter in the Vamana literature. Larger values improve recall at the cost of search time. - -FAISS Indexes -============= - -faiss_gpu_flat --------------- - -Use FAISS flat index on the GPU, which performs an exact search using brute-force and doesn't have any further build or search parameters. - -faiss_gpu_ivf_flat ------------------- - -IVF-flat uses an inverted-file index, which partitions the vectors into a series of clusters, or lists, storing them in an interleaved format which is optimized for fast distance computation. The searching of an IVF-flat index reduces the total vectors in the index to those within some user-specified nearest clusters called probes. - -IVF-flat is a simple algorithm which won't save any space, but it provides competitive search times even at higher levels of recall. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlists` - - `build` - - Y - - Positive integer >0 - - - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - 20 - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - -faiss_gpu_ivf_pq ----------------- - -IVF-pq is an inverted-file index, which partitions the vectors into a series of clusters, or lists, in a similar way to IVF-flat above. The difference is that IVF-PQ uses product quantization to also compress the vectors, giving the index a smaller memory footprint. Unfortunately, higher levels of compression can also shrink recall, which a refinement step can improve when the original vectors are still available. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlist` - - `build` - - Y - - Positive integer >0 - - - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained. - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `M_ratio` - - `build` - - Y - - Positive integer. Power of 2 [8-64] - - - - Ratio of number of chunks or subquantizers for each vector. Computed by `dims` / `M_ratio` - - * - `usePrecomputed` - - `build` - - N - - Boolean - - `false` - - Use pre-computed lookup tables to speed up search at the cost of increased memory usage. - - * - `useFloat16` - - `build` - - N - - Boolean - - `false` - - Use half-precision floats for clustering step. - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - * - `refine_ratio` - - `search` - - N - - Positive number >=1 - - 1 - - `refine_ratio * k` nearest neighbors are queried from the index initially and an additional refinement step improves recall by selecting only the best `k` neighbors. - - -faiss_cpu_flat --------------- - -Use FAISS flat index on the CPU, which performs an exact search using brute-force and doesn't have any further build or search parameters. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `numThreads` - - `search` - - N - - Positive integer >0 - - 1 - - Number of threads to use for queries. - -faiss_cpu_ivf_flat ------------------- - -Use FAISS IVF-Flat index on CPU - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlists` - - `build` - - Y - - Positive integer >0 - - - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - * - `numThreads` - - `search` - - N - - Positive integer >0 - - 1 - - Number of threads to use for queries. - -faiss_cpu_ivf_pq ----------------- - -Use FAISS IVF-PQ index on CPU - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `nlist` - - `build` - - Y - - Positive integer >0 - - - - Number of clusters to partition the vectors into. Larger values will put less points into each cluster but this will impact index build time as more clusters need to be trained. - - * - `ratio` - - `build` - - N - - Positive integer >0 - - 2 - - `1/ratio` is the number of training points which should be used to train the clusters. - - * - `M` - - `build` - - Y - - Positive integer. Power of 2 [8-64] - - - - Ratio of number of chunks or subquantizers for each vector. Computed by `dims` / `M_ratio` - - * - `usePrecomputed` - - `build` - - N - - Boolean - - `false` - - Use pre-computed lookup tables to speed up search at the cost of increased memory usage. - - * - `bitsPerCode` - - `build` - - N - - Positive integer [4-8] - - 8 - - Number of bits for representing each quantized code. - - * - `nprobe` - - `search` - - Y - - Positive integer >0 - - - - The closest number of clusters to search for each query vector. Larger values will improve recall but will search more points in the index. - - * - `refine_ratio` - - `search` - - N - - Positive number >=1 - - 1 - - `refine_ratio * k` nearest neighbors are queried from the index initially and an additional refinement step improves recall by selecting only the best `k` neighbors. - - * - `numThreads` - - `search` - - N - - Positive integer >0 - - 1 - - Number of threads to use for queries. - -HNSW -==== - -cuvs_hnsw ---------- - -cuVS HNSW builds an HNSW index using the ACE (Augmented Core Extraction) algorithm, which enables GPU-accelerated HNSW index construction for datasets too large to fit in GPU memory. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `hierarchy` - - `build` - - N - - [`NONE`, `CPU`, `GPU`] - - `NONE` - - Type of HNSW hierarchy to build. `NONE` creates a base-layer-only index, `CPU` builds full hierarchy on CPU, `GPU` builds full hierarchy on GPU. - - * - `efConstruction` - - `build` - - Y - - Positive integer >0 - - - - Controls index time and accuracy. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. - - * - `M` - - `build` - - Y - - Positive integer. Often between 2-100 - - - - Number of bi-directional links create for every new element during construction. Higher values work for higher intrinsic dimensionality and/or high recall, low values can work for datasets with low intrinsic dimensionality and/or low recalls. Also affects the algorithm's memory consumption. - - * - `numThreads` - - `build` - - N - - Positive integer >0 - - 1 - - Number of threads to use to build the index. - - * - `npartitions` - - `build` - - N - - Positive integer >0 - - 1 - - Number of partitions to use for the ACE build. Small values might improve recall but potentially degrade performance and increase memory usage. The partition size is on average 2 * (n_rows / npartitions) * dim * sizeof(T). 2 is because of the core and augmented vectors. Please account for imbalance in the partition sizes (up to 3x in our tests). - - * - `ef_construction` - - `build` - - N - - Positive integer >0 - - 120 - - Controls index time and accuracy when using ACE build. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. - - * - `build_dir` - - `build` - - N - - String - - "/tmp/ace_build" - - The directory to use for the ACE build. This should be the fastest disk in the system and hold enough space for twice the dataset, final graph, and label mapping. - - * - `use_disk` - - `build` - - N - - Boolean - - `false` - - Whether to use disk-based storage for ACE build. When true, forces ACE to use disk-based storage even if the graph fits in host and GPU memory. When false, ACE will use in-memory storage if the graph fits in host and GPU memory and disk-based storage otherwise. - - * - `ef` - - `search` - - Y - - Positive integer >0 - - - - Size of the dynamic list for the nearest neighbors used for search. Higher value leads to more accurate but slower search. Cannot be lower than `k`. - - * - `numThreads` - - `search` - - N - - Positive integer >0 - - 1 - - Number of threads to use for queries. - -hnswlib -------- - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `efConstruction` - - `build` - - Y - - Positive integer >0 - - - - Controls index time and accuracy. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. - - * - `M` - - `build` - - Y - - Positive integer. Often between 2-100 - - - - Number of bi-directional links create for every new element during construction. Higher values work for higher intrinsic dimensionality and/or high recall, low values can work for datasets with low intrinsic dimensionality and/or low recalls. Also affects the algorithm's memory consumption. - - * - `numThreads` - - `build` - - N - - Positive integer >0 - - 1 - - Number of threads to use to build the index. - - * - `ef` - - `search` - - Y - - Positive integer >0 - - - - Size of the dynamic list for the nearest neighbors used for search. Higher value leads to more accurate but slower search. Cannot be lower than `k`. - - * - `numThreads` - - `search` - - N - - Positive integer >0 - - 1 - - Number of threads to use for queries. - -Please refer to `HNSW algorithm parameters guide `_ from `hnswlib` to learn more about these arguments. - -DiskANN -======= - -diskann_memory --------------- - -Use DiskANN in-memory index for approximate search. - -.. list-table:: - - * - Parameter - - Type - - Required - - Data Type - - Default - - Description - - * - `R` - - `build` - - Y - - Positive integer >0 - - - - Maximum degree of the graph index - - * - `L_build` - - `build` - - Y - - Positive integer >0 - - - - number of visited nodes per greedy search during graph construction - - * - `alpha` - - `build` - - N - - Positive number >=1 - - 1.2 - - controls the pruning parameter of the graph construction - - * - `num_threads` - - `build` - - N - - Positive integer >0 - - omp_get_max_threads() - - Number of CPU threads to use to build the index. - - * - `L_search` - - `search` - - Y - - Positive integer >0 - - - - visited list size during search diff --git a/docs/source/cuvs_bench/pluggable_backend.rst b/docs/source/cuvs_bench/pluggable_backend.rst deleted file mode 100644 index 3655c1b0b6..0000000000 --- a/docs/source/cuvs_bench/pluggable_backend.rst +++ /dev/null @@ -1,241 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~~ -Pluggable Backend -~~~~~~~~~~~~~~~~~~~~~~~~~ - -cuVS Bench uses a pluggable API so that benchmarks can be run through different execution paths. The default path runs C++ benchmark executables; other backends (e.g. Elasticsearch, Milvus) can be added by implementing the same interface and registering them. Two pieces work together: a **config loader** turns the user's arguments (dataset, algorithms, k, batch_size, and the like) into a structured configuration; a **backend** takes that configuration and runs build and search. Both are registered under a backend type name (e.g. ``cpp_gbench``). When ``BenchmarkOrchestrator(backend_type="cpp_gbench").run_benchmark(...)`` is called, the orchestrator uses the config loader for that type to produce the configuration, then passes it to the backend for that type. - -The following shows how the default backend is used: - -.. code-block:: python - - from cuvs_bench.orchestrator import BenchmarkOrchestrator - - orchestrator = BenchmarkOrchestrator(backend_type="cpp_gbench") - results = orchestrator.run_benchmark( - dataset="deep-image-96-inner", - algorithms="cuvs_cagra", - count=10, - batch_size=10, - build=True, - search=True, - ) - -How a run flows ---------------- - -1. The user calls ``orchestrator.run_benchmark(backend_type="...", dataset=..., algorithms=..., count=..., **kwargs)``. - -2. The orchestrator looks up the **config loader** for that ``backend_type`` and calls its **load()** method. The loader reads YAML (or other sources), expands parameter combinations, applies constraints, and returns a **DatasetConfig** and a list of **BenchmarkConfig** (each describing one or more index configs: algorithm, build params, search params). - -3. The orchestrator obtains the **backend** for that ``backend_type`` from the **BackendRegistry** (instantiating it with the config it needs, e.g. executable path, host/port). - -4. The orchestrator calls the backend's **build(dataset, indexes, ...)** then **search(dataset, indexes, k, batch_size, ...)**. The backend uses the same config shape that its loader produced. - -5. The backend returns **BuildResult** and **SearchResult**; the orchestrator aggregates and returns them. - -The config loader and the backend are thus a pair: the loader defines what to run (which algorithms and parameters); the backend defines how it runs (C++ subprocess, HTTP to a service, and so on). - -What the config loader produces -------------------------------- - -The orchestrator calls the config loader's **load()** method with the same arguments passed to ``run_benchmark()`` (e.g. ``dataset``, ``dataset_path``, ``algorithms``, ``count``, ``batch_size``, ``groups``, ``algo_groups``, and backend-specific options). The loader must return two things: - -- **DatasetConfig** – Dataset metadata: ``name``, ``base_file``, ``query_file``, ``groundtruth_neighbors_file``, ``distance`` (e.g. ``"euclidean"``), ``dims``, and optional ``subset_size``. These are used by the orchestrator to build the in-memory ``Dataset`` and by the backend if it needs file paths. - -- **List[BenchmarkConfig]** – Each **BenchmarkConfig** has: - - **indexes**: a list of **IndexConfig**. Each **IndexConfig** has ``name`` (e.g. ``"my_algo.param1value"``), ``algo`` (algorithm name), ``build_param`` (dict of build parameters), ``search_params`` (list of dicts, one per search parameter combination to benchmark), and ``file`` (path or identifier where the index is stored). - - **backend_config**: a dict passed to the backend constructor (e.g. ``executable_path`` for C++, or ``host``, ``port``, ``index_name`` for a network backend). The backend receives this as its ``config`` in ``__init__``. - -The following shows how to construct a minimal ``DatasetConfig`` and one ``BenchmarkConfig`` (one index, one search param set) so the backend runs a single build and search configuration: - -.. code-block:: python - - from cuvs_bench.orchestrator.config_loaders import ( - ConfigLoader, - DatasetConfig, - BenchmarkConfig, - IndexConfig, - ) - - class MyConfigLoader(ConfigLoader): - @property - def backend_type(self) -> str: - return "my_backend" - - def load(self, dataset, dataset_path, algorithms, count=10, batch_size=10000, **kwargs): - path_to_base = ... # path to base vectors file - path_to_queries = ... # path to query file - path_to_groundtruth = ... # path to groundtruth neighbors file - path_to_index = ... # path or id where the index is stored - dataset_config = DatasetConfig( - name=dataset, - base_file=path_to_base, - query_file=path_to_queries, - groundtruth_neighbors_file=path_to_groundtruth, - distance="euclidean", - dims=128, - ) - index = IndexConfig( - name=f"{algorithms}.default", - algo=algorithms, - build_param={"nlist": 1024}, - search_params=[{"nprobe": 10}], - file=path_to_index, - ) - benchmark_config = BenchmarkConfig( - indexes=[index], - backend_config={ - "host": ..., # backend host - "port": ..., # backend port - "index_name": ..., # name of the index on the backend - }, - ) - return dataset_config, [benchmark_config] - -Adding a new backend --------------------- - -To add a new execution path (e.g. Elasticsearch): - -1. Implement a **config loader**. Subclass **ConfigLoader** (from ``cuvs_bench.orchestrator.config_loaders``). Implement **load()** to accept the kwargs the orchestrator passes (dataset, dataset_path, algorithms, count, batch_size, and the like) and return ``(DatasetConfig, List[BenchmarkConfig])``. Populate **DatasetConfig** with dataset paths and metadata; for each run you want, add an **IndexConfig** (name, algo, build_param, search_params, file) and a **BenchmarkConfig** (indexes, backend_config). The **backend_config** dict is passed to your backend's constructor. Register the loader with **register_config_loader("my_backend", MyConfigLoader)**. - -2. Implement the **backend**. Subclass **BenchmarkBackend** (from ``cuvs_bench.backends.base``). In **__init__(self, config)**, store the config (this is the **backend_config** produced by the loader). Implement **build(dataset, indexes, force=False, dry_run=False)** to return a **BuildResult** (index_path, build_time_seconds, index_size_bytes, algorithm, build_params, metadata, success). Implement **search(dataset, indexes, k, batch_size, mode=..., ...)** to return a **SearchResult** (neighbors, distances, search_time_ms, queries_per_second, recall, algorithm, search_params, success). Implement the **algo** property (e.g. from ``self.config["algo"]``). Set **requires_gpu** or **requires_network** in config if the backend needs them. Register the class with **get_registry().register("my_backend", MyBackend)**. - -3. Use the new backend by calling ``BenchmarkOrchestrator(backend_type="my_backend").run_benchmark(dataset=..., dataset_path=..., algorithms=..., **kwargs)``. The orchestrator will use your loader to build the configuration and your backend to run build and search. - -After implementing your loader and backend, register them as follows: - -.. code-block:: python - - from cuvs_bench.orchestrator import register_config_loader - from cuvs_bench.backends import get_registry - - register_config_loader("my_backend", MyConfigLoader) - get_registry().register("my_backend", MyBackend) - -Example: adding an Elasticsearch backend ------------------------------------------ - -The following example shows a minimal Elasticsearch-style backend. The config loader builds one dataset config and one benchmark config with a single index; the backend stubs build and search and returns the result types the orchestrator expects. In practice you would replace the stub logic with real Elasticsearch API calls. - -Config loader: the **load()** method receives ``dataset``, ``dataset_path``, ``algorithms``, ``count``, ``batch_size``, and optional kwargs. It returns a **DatasetConfig** (filled from dataset path and name) and a list of one **BenchmarkConfig** containing one **IndexConfig** and a **backend_config** with ``host``, ``port``, and ``index_name`` for the backend to use. - -.. code-block:: python - - from cuvs_bench.orchestrator.config_loaders import ( - ConfigLoader, - DatasetConfig, - BenchmarkConfig, - IndexConfig, - ) - - class ElasticsearchConfigLoader(ConfigLoader): - @property - def backend_type(self) -> str: - return "elasticsearch" - - def load(self, dataset, dataset_path, algorithms, count=10, batch_size=10000, **kwargs): - path_to_base = ... # path to base vectors (e.g. from dataset_path/dataset) - path_to_queries = ... # path to query vectors - path_to_groundtruth = ... # path to groundtruth file - path_to_index = ... # path or id for the index - dataset_config = DatasetConfig( - name=dataset, - base_file=path_to_base, - query_file=path_to_queries, - groundtruth_neighbors_file=path_to_groundtruth, - distance="euclidean", - dims=kwargs.get("dims", 128), - ) - index = IndexConfig( - name=f"{algorithms}.es", - algo=algorithms, - build_param={}, - search_params=[{"ef_search": 100}], - file=path_to_index, - ) - benchmark_config = BenchmarkConfig( - indexes=[index], - backend_config={ - "host": ..., # Elasticsearch host - "port": ..., # Elasticsearch port - "index_name": ..., # name of the vector index - "algo": algorithms, - }, - ) - return dataset_config, [benchmark_config] - -Backend: the backend is constructed with **backend_config** (host, port, index_name, algo). **build()** and **search()** return **BuildResult** and **SearchResult** with the required fields; here they are stubbed with minimal values. Replace the stub body with actual Elasticsearch index creation and search calls. - -.. code-block:: python - - import numpy as np - from cuvs_bench.backends.base import ( - BenchmarkBackend, - Dataset, - BuildResult, - SearchResult, - ) - from cuvs_bench.orchestrator.config_loaders import IndexConfig - - class ElasticsearchBackend(BenchmarkBackend): - @property - def algo(self) -> str: - return self.config.get("algo", "elasticsearch") - - def build(self, dataset, indexes, force=False, dry_run=False): - # Stub: in practice, create ES index and bulk-index dataset.base_vectors - return BuildResult( - index_path=indexes[0].file if indexes else "", - build_time_seconds=0.0, - index_size_bytes=0, - algorithm=self.algo, - build_params=indexes[0].build_param if indexes else {}, - metadata={}, - success=True, - ) - - def search(self, dataset, indexes, k, batch_size=10000, mode="latency", force=False, search_threads=None, dry_run=False): - # Stub: in practice, run ES kNN search and compute recall - n_queries = dataset.n_queries - return SearchResult( - neighbors=np.zeros((n_queries, k), dtype=np.int64), - distances=np.zeros((n_queries, k), dtype=np.float32), - search_time_ms=0.0, - queries_per_second=0.0, - recall=0.0, - algorithm=self.algo, - search_params=indexes[0].search_params if indexes else [], - success=True, - ) - -Registration: - -.. code-block:: python - - from cuvs_bench.orchestrator import register_config_loader - from cuvs_bench.backends import get_registry - - register_config_loader("elasticsearch", ElasticsearchConfigLoader) - get_registry().register("elasticsearch", ElasticsearchBackend) - -The built-in **CppGoogleBenchmarkBackend** (``backend_type="cpp_gbench"``) is one such pair: **CppGBenchConfigLoader** reads the YAML under ``config/datasets`` and ``config/algos``, expands the Cartesian product, and validates with the constraint functions; the backend runs the C++ benchmark executables and merges results. Adding a new C++ algorithm (see :doc:`index`) only adds another executable and config for this backend; it does not add a new backend. - -Components at a glance ----------------------- - -.. list-table:: - :header-rows: 1 - :widths: 20 80 - - * - Component - - Description - - * - ConfigLoader - - Abstract. **load(**kwargs)** returns ``(DatasetConfig, List[BenchmarkConfig])``. Register with **register_config_loader(backend_type, loader_class)**. - - * - BenchmarkBackend - - Abstract. **build(dataset, indexes, force, dry_run)** returns ``BuildResult``; **search(dataset, indexes, k, batch_size, mode, ...)** returns ``SearchResult``. Optional **initialize()** and **cleanup()**. Properties: **algo**, **requires_gpu**, **requires_network** (from config). Register with **BackendRegistry.register(name, backend_class)**; get an instance with **get_backend(name, config)**. - - * - BackendRegistry - - **get_registry()** returns the singleton. **register(name, backend_class)** and **get_backend(name, config)** tie a backend type name to the class and to instances. diff --git a/docs/source/developer_guide.md b/docs/source/developer_guide.md deleted file mode 100644 index c323de0286..0000000000 --- a/docs/source/developer_guide.md +++ /dev/null @@ -1,418 +0,0 @@ -# Developer Guide - -## General -Please start by reading the [Contributor Guide](contributing.md). - -## Performance -1. In performance critical sections of the code, favor `cudaDeviceGetAttribute` over `cudaDeviceGetProperties`. See corresponding CUDA devblog [here](https://devblogs.nvidia.com/cuda-pro-tip-the-fast-way-to-query-device-properties/) to know more. -2. If an algo requires you to launch GPU work in multiple cuda streams, do not create multiple `raft::resources` objects, one for each such work stream. Instead, use the stream pool configured on the given `raft::resources` instance's `raft::resources::get_stream_from_stream_pool()` to pick up the right cuda stream. Refer to the section on [CUDA Resources](#resource-management) and the section on [Threading](#threading-model) for more details. TIP: use `raft::resources::get_stream_pool_size()` to know how many such streams are available at your disposal. - - -## Local Development - -Developing features and fixing bugs for the RAFT library itself is straightforward and only requires building and installing the relevant RAFT artifacts. - -The process for working on a CUDA/C++ feature which might span RAFT and one or more consuming libraries can vary slightly depending on whether the consuming project relies on a source build (as outlined in the [BUILD](BUILD.md#install_header_only_cpp) docs). In such a case, the option `CPM_raft_SOURCE=/path/to/raft/source` can be passed to the cmake of the consuming project in order to build the local RAFT from source. The PR with relevant changes to the consuming project can also pin the RAFT version temporarily by explicitly changing the `FORK` and `PINNED_TAG` arguments to the RAFT branch containing their changes when invoking `find_and_configure_raft`. The pin should be reverted after the change is merged to the RAFT project and before it is merged to the dependent project(s) downstream. - -If building a feature which spans projects and not using the source build in cmake, the RAFT changes (both C++ and Python) will need to be installed into the environment of the consuming project before they can be used. The ideal integration of RAFT into consuming projects will enable both the source build in the consuming project only for this case but also rely on a more stable packaging (such as conda packaging) otherwise. - - -## Threading Model - -With the exception of the `raft::resources`, RAFT algorithms should maintain thread-safety and are, in general, -assumed to be single threaded. This means they should be able to be called from multiple host threads so -long as different instances of `raft::resources` are used. - -Exceptions are made for algorithms that can take advantage of multiple CUDA streams within multiple host threads -in order to oversubscribe or increase occupancy on a single GPU. In these cases, the use of multiple host -threads within RAFT algorithms should be used only to maintain concurrency of the underlying CUDA streams. -Multiple host threads should be used sparingly, be bounded, and should steer clear of performing CPU-intensive -computations. - -A good example of an acceptable use of host threads within a RAFT algorithm might look like the following - -```cpp -#include -#include -#include -raft::resources res; - -... - -sync_stream(res); - -... - -int n_streams = get_stream_pool_size(res); - -#pragma omp parallel for num_threads(n_threads) -for(int i = 0; i < n; i++) { - int thread_num = omp_get_thread_num() % n_threads; - cudaStream_t s = get_stream_from_stream_pool(res, thread_num); - ... possible light cpu pre-processing ... - my_kernel1<<>>(...); - ... - ... some possible async d2h / h2d copies ... - my_kernel2<<>>(...); - ... - sync_stream(res, s); - ... possible light cpu post-processing ... -} -``` - -In the example above, if there is no CPU pre-processing at the beginning of the for-loop, an event can be registered in -each of the streams within the for-loop to make them wait on the stream from the handle. If there is no CPU post-processing -at the end of each for-loop iteration, `sync_stream(res, s)` can be replaced with a single `sync_stream_pool(res)` -after the for-loop. - -To avoid compatibility issues between different threading models, the only threading programming allowed in RAFT is OpenMP. -Though RAFT's build enables OpenMP by default, RAFT algorithms should still function properly even when OpenMP has been -disabled. If the CPU pre- and post-processing were not needed in the example above, OpenMP would not be needed. - -The use of threads in third-party libraries is allowed, though they should still avoid depending on a specific OpenMP runtime. - -## Public Interface - -### General guidelines -Functions exposed via the C++ API must be stateless. Things that are OK to be exposed on the interface: -1. Any [POD](https://en.wikipedia.org/wiki/Passive_data_structure) - see [std::is_pod](https://en.cppreference.com/w/cpp/types/is_pod) as a reference for C++11 POD types. -2. `raft::resources` - since it stores resource-related state which has nothing to do with model/algo state. -3. Avoid using pointers to POD types (explicitly putting it out, even though it can be considered as a POD) and pass the structures by reference instead. - Internal to the C++ API, these stateless functions are free to use their own temporary classes, as long as they are not exposed on the interface. -4. Accept single- (`raft::span`) and multi-dimensional views (`raft::mdspan`) and validate their metadata wherever possible. -5. Prefer `std::optional` for any optional arguments (e.g. do not accept `nullptr`) -6. All public APIs should be lightweight wrappers around calls to private APIs inside the `detail` namespace. - -### API stability - -Since RAFT is a core library with multiple consumers, it's important that the public APIs maintain stability across versions and any changes to them are done with caution, adding new functions and deprecating the old functions over a couple releases as necessary. - -### Stateless C++ APIs - -Using the IVF-PQ algorithm as an example, the following way of exposing its API would be wrong according to the guidelines in this section, since it exposes a non-POD C++ class object in the C++ API: -```cpp -template -class ivf_pq { - ivf_pq_params params_; - raft::resources const& res_; - -public: - ivf_pq(raft::resources const& res); - void train(raft::device_matrix dataset); - void search(raft::device_matrix queries, - raft::device_matrix out_inds, - raft::device_matrix out_dists); -}; -``` - -An alternative correct way to expose this could be: -```cpp -namespace raft::ivf_pq { - -template -void ivf_pq_train(raft::resources const& res, const raft::ivf_pq_params ¶ms, raft::ivf_pq_index &index, -raft::device_matrix dataset); - -template -void ivf_pq_search(raft::resources const& res, raft::ivf_pq_params const¶ms, raft::ivf_pq_index const & index, -raft::device_matrix queries, -raft::device_matrix out_inds, -raft::device_matrix out_dists); -} -``` - -### Other functions on state - -These guidelines also mean that it is the responsibility of C++ API to expose methods to load and store (aka marshalling) such a data structure. Further continuing the IVF-PQ example, the following methods could achieve this: -```cpp -namespace raft::ivf_pq { - void save(raft::ivf_pq_index const& model, std::ostream &os); - void load(raft::ivf_pq_index& model, std::istream &is); -} -``` - - -## Coding style - -### Code Formatting - -#### Using pre-commit hooks - -RAFT uses [pre-commit](https://pre-commit.com/) to execute all code linters and formatters. These -tools ensure a consistent code format throughout the project. Using pre-commit ensures that linter -versions and options are aligned for all developers. Additionally, there is a CI check in place to -enforce that committed code follows our standards. - -To use `pre-commit`, install via `conda` or `pip`: - -```bash -conda install -c conda-forge pre-commit -``` - -```bash -pip install pre-commit -``` - -Then run pre-commit hooks before committing code: - -```bash -pre-commit run -``` - -By default, pre-commit runs on staged files (only changes and additions that will be committed). -To run pre-commit checks on all files, execute: - -```bash -pre-commit run --all-files -``` - -Optionally, you may set up the pre-commit hooks to run automatically when you make a git commit. This can be done by running: - -```bash -pre-commit install -``` - -Now code linters and formatters will be run each time you commit changes. - -You can skip these checks with `git commit --no-verify` or with the short version `git commit -n`. - -#### Summary of pre-commit hooks - -The following section describes some of the core pre-commit hooks used by the repository. -See `.pre-commit-config.yaml` for a full list. - -C++/CUDA is formatted with [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html). - -RAFT relies on `clang-format` to enforce code style across all C++ and CUDA source code. The coding style is based on the [Google style guide](https://google.github.io/styleguide/cppguide.html#Formatting). The only digressions from this style are the following. -1. Do not split empty functions/records/namespaces. -2. Two-space indentation everywhere, including the line continuations. -3. Disable reflowing of comments. - The reasons behind these deviations from the Google style guide are given in comments [here](https://github.com/rapidsai/cuvs/blob/main/cpp/.clang-format). - -[`doxygen`](https://doxygen.nl/) is used as documentation generator and also as a documentation linter. -In order to run doxygen as a linter on C++/CUDA code, run - -```bash -./ci/checks/doxygen.sh -``` - -Python code runs several linters including [Black](https://black.readthedocs.io/en/stable/), -[isort](https://pycqa.github.io/isort/), and [flake8](https://flake8.pycqa.org/en/latest/). - -RAFT also uses [codespell](https://github.com/codespell-project/codespell) to find spelling -mistakes, and this check is run as a pre-commit hook. To apply the suggested spelling fixes, -you can run `codespell -i 3 -w .` from the repository root directory. -This will bring up an interactive prompt to select which spelling fixes to apply. - -### #include style -[include_checker.py](https://github.com/rapidsai/cuvs/blob/main/cpp/scripts/include_checker.py) is used to enforce the include style as follows: -1. `#include "..."` should be used for referencing local files only. It is acceptable to be used for referencing files in a sub-folder/parent-folder of the same algorithm, but should never be used to include files in other algorithms or between algorithms and the primitives or other dependencies. -2. `#include <...>` should be used for referencing everything else - -Manually, run the following to bulk-fix include style issues: -```bash -python ./cpp/scripts/include_checker.py --inplace [cpp/include cpp/tests ... list of folders which you want to fix] -``` - -### Copyright header -RAPIDS [pre-commit-hooks](https://github.com/rapidsai/pre-commit-hooks) checks the Copyright -header for all git-modified files. - -Manually, you can run the following to bulk-fix the header on all files in the repository: -```bash -pre-commit run -a verify-copyright -``` -Keep in mind that this only applies to files tracked by git that have been modified. - -## Error handling -Call CUDA APIs via the provided helper macros `RAFT_CUDA_TRY`, `RAFT_CUBLAS_TRY` and `RAFT_CUSOLVER_TRY`. These macros take care of checking the return values of the used API calls and generate an exception when the command is not successful. If you need to avoid an exception, e.g. inside a destructor, use `RAFT_CUDA_TRY_NO_THROW`, `RAFT_CUBLAS_TRY_NO_THROW ` and `RAFT_CUSOLVER_TRY_NO_THROW`. These macros log the error but do not throw an exception. - -## Common Design Considerations - -1. Use the `hpp` extension for files which can be compiled with `gcc` against the CUDA-runtime. Use the `cuh` extension for files which require `nvcc` to be compiled. `hpp` can also be used for functions marked `__host__ __device__` only if proper checks are in place to remove the `__device__` designation when not compiling with `nvcc`. - -2. When additional classes, structs, or general POCO types are needed to be used for representing data in the public API, place them in a new file called `_types.hpp`. This tells users they are safe to expose these types on their own public APIs without bringing in device code. At a minimum, the definitions for these types, at least, should not require `nvcc`. In general, these classes should only store very simple state and should not perform their own computations. Instead, new functions should be exposed on the public API which accept these objects, reading or updating their state as necessary. - -3. Documentation for public APIs should be well documented, easy to use, and it is highly preferred that they include usage instructions. - -4. Before creating a new primitive, check to see if one exists already. If one exists but the API isn't flexible enough to include your use-case, consider first refactoring the existing primitive. If that is not possible without an extreme number of changes, consider how the public API could be made more flexible. If the new primitive is different enough from all existing primitives, consider whether an existing public API could invoke the new primitive as an option or argument. If the new primitive is different enough from what exists already, add a header for the new public API function to the appropriate subdirectory and namespace. - -## Testing - -It's important for RAFT to maintain a high test coverage of the public APIs in order to minimize the potential for downstream projects to encounter unexpected build or runtime behavior as a result of changes. - -A well-defined public API can help maintain compile-time stability but means more focus should be placed on testing the functional requirements and verifying execution on the various edge cases within RAFT itself. Ideally, bug fixes and new features should be able to be made to RAFT independently of the consuming projects. - -## Documentation - -Public APIs always require documentation since those will be exposed directly to users. For C++, we use [doxygen](http://www.doxygen.nl) and for Python/cython we use [pydoc](https://docs.python.org/3/library/pydoc.html). In addition to summarizing the purpose of each class / function in the public API, the arguments (and relevant templates) should be documented along with brief usage examples. - -## Asynchronous operations and stream ordering -All RAFT algorithms should be as asynchronous as possible avoiding the use of the default stream (aka as NULL or `0` stream). Implementations that require only one CUDA Stream should use the stream from `raft::resources`: - -```cpp -#include -#include - -void foo(const raft::resources& res, ...) -{ - cudaStream_t stream = get_cuda_stream(res); -} -``` -When multiple streams are needed, e.g. to manage a pipeline, use the internal streams available in `raft::resources` (see [CUDA Resources](#cuda-resources)). If multiple streams are used all operations still must be ordered according to `raft::resource::get_cuda_stream()` (from `raft/core/resource/cuda_stream.hpp`). Before any operation in any of the internal CUDA streams is started, all previous work in `raft::resource::get_cuda_stream()` must have completed. Any work enqueued in `raft::resource::get_cuda_stream()` after a RAFT function returns should not start before all work enqueued in the internal streams has completed. E.g. if a RAFT algorithm is called like this: -```cpp -#include -#include -void foo(const double* srcdata, double* result) -{ - cudaStream_t stream; - CUDA_RT_CALL( cudaStreamCreate( &stream ) ); - raft::resources res; - set_cuda_stream(res, stream); - - ... - - RAFT_CUDA_TRY( cudaMemcpyAsync( srcdata, h_srcdata.data(), n*sizeof(double), cudaMemcpyHostToDevice, stream ) ); - - raft::algo(raft::resources, dopredict, srcdata, result, ... ); - - RAFT_CUDA_TRY( cudaMemcpyAsync( h_result.data(), result, m*sizeof(int), cudaMemcpyDeviceToHost, stream ) ); - - ... -} -``` -No work in any stream should start in `raft::algo` before the `cudaMemcpyAsync` in `stream` launched before the call to `raft::algo` is done. And all work in all streams used in `raft::algo` should be done before the `cudaMemcpyAsync` in `stream` launched after the call to `raft::algo` starts. - -This can be ensured by introducing interstream dependencies with CUDA events and `cudaStreamWaitEvent`. For convenience, the header `raft/core/device_resources.hpp` provides the class `raft::stream_syncer` which lets all `raft::resources` internal CUDA streams wait on `raft::resource::get_cuda_stream()` in its constructor and in its destructor and lets `raft::resource::get_cuda_stream()` wait on all work enqueued in the `raft::resources` internal CUDA streams. The intended use would be to create a `raft::stream_syncer` object as the first thing in an entry function of the public RAFT API: - -```cpp -namespace raft { - void algo(const raft::resources& res, ...) - { - raft::streamSyncer _(res); - } -} -``` -This ensures the stream ordering behavior described above. - -### Using Thrust -To ensure that thrust algorithms are executed in the intended stream the `thrust::cuda::par` execution policy should be used. To ensure that thrust algorithms allocate temporary memory via the provided device memory allocator, use the `rmm::exec_policy` available in `raft/core/resource/thrust_policy.hpp`, which can be used through `raft::resources`: -```cpp -#include -#include -void foo(const raft::resources& res, ...) -{ - auto execution_policy = get_thrust_policy(res); - thrust::for_each(execution_policy, ... ); -} -``` - -## Resource Management - -Do not create reusable CUDA resources directly in implementations of RAFT algorithms. Instead, use the existing resources in `raft::resources` to avoid constant creation and deletion of reusable resources such as CUDA streams, CUDA events or library handles. Please file a feature request if a resource handle is missing in `raft::resources`. -The resources can be obtained like this -```cpp -#include -#include -#include -void foo(const raft::resources& h, ...) -{ - cublasHandle_t cublasHandle = get_cublas_handle(h); - const int num_streams = get_stream_pool_size(h); - const int stream_idx = ... - cudaStream_t stream = get_stream_from_stream_pool(stream_idx); - ... -} -``` - -The example below shows one way to create `n_stream` number of internal cuda streams with an `rmm::stream_pool` which can later be used by the algos inside RAFT. -```cpp -#include -#include -#include -int main(int argc, char** argv) -{ - int n_streams = argc > 1 ? atoi(argv[1]) : 0; - raft::resources res; - set_cuda_stream_pool(res, std::make_shared(n_streams)); - - foo(res, ...); -} -``` - -## Multi-GPU - -The multi-GPU paradigm of RAFT is **O**ne **P**rocess per **G**PU (OPG). Each algorithm should be implemented in a way that it can run with a single GPU without any specific dependencies to a particular communication library. A multi-GPU implementation should use the methods offered by the class `raft::comms::comms_t` from [raft/core/comms.hpp] for inter-rank/GPU communication. It is the responsibility of the user of cuML to create an initialized instance of `raft::comms::comms_t`. - -E.g. with a CUDA-aware MPI, a RAFT user could use code like this to inject an initialized instance of `raft::comms::mpi_comms` into a `raft::resources`: - -```cpp -#include -#include -#include -#include -... -int main(int argc, char * argv[]) -{ - MPI_Init(&argc, &argv); - int rank = -1; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - - int local_rank = -1; - { - MPI_Comm local_comm; - MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &local_comm); - - MPI_Comm_rank(local_comm, &local_rank); - - MPI_Comm_free(&local_comm); - } - - cudaSetDevice(local_rank); - - mpi_comms raft_mpi_comms; - MPI_Comm_dup(MPI_COMM_WORLD, &raft_mpi_comms); - - { - raft::resources res; - initialize_mpi_comms(res, raft_mpi_comms); - - ... - - raft::algo(res, ... ); - } - - MPI_Comm_free(&raft_mpi_comms); - - MPI_Finalize(); - return 0; -} -``` - -A RAFT developer can assume the following: -* An instance of `raft::comms::comms_t` was correctly initialized. -* All processes that are part of `raft::comms::comms_t` call into the RAFT algorithm cooperatively. - -The initialized instance of `raft::comms::comms_t` can be accessed from the `raft::resources` instance: - -```cpp -#include -#include -void foo(const raft::resources& res, ...) -{ - const raft::comms_t& communicator = get_comms(res); - const int rank = communicator.get_rank(); - const int size = communicator.get_size(); - ... -} -``` - -## Using Just-in-Time Link-Time Optimization - -cuVS is moving to using link-time optimization for new kernels, and this requires some changes to the way kernels are written. Instead of compiling all kernel variants at build time (which leads to binary size explosion), JIT LTO compiles kernel fragments separately and links them together at runtime based on the specific configuration needed. - -This approach ultimately enables: -- **Reduced binary size**: Compile fragments once, combine many ways -- **User Defined Functions**: Link UDFs in cuVS CUDA kernels - -For more information on JIT LTO, see [Advanced Topics](advanced_topics). For a complete guide on implementing JIT LTO kernels, including step-by-step examples, see the [JIT LTO Guide](jit_lto_guide.md). diff --git a/docs/source/filtering.rst b/docs/source/filtering.rst deleted file mode 100644 index cb168f94c8..0000000000 --- a/docs/source/filtering.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. _filtering: - -~~~~~~~~~~~~~~~~~~~~~~~~ -Filtering vector indexes -~~~~~~~~~~~~~~~~~~~~~~~~ - -cuVS supports different type of filtering depending on the vector index being used. The main method used in all of the vector indexes -is pre-filtering, which is a technique that will take into account the filtering of the vectors before computing its closest neighbors, saving -some computation from calculating distances. - -Bitset -====== - -A bitset is an array of bits where each bit can have two possible values: `0` and `1`, which signify in the context of filtering whether -a sample should be filtered or not. `0` means that the corresponding vector will be filtered, and will therefore not be present in the results of the search. -This mechanism is optimized to take as little memory space as possible, and is available through the RAFT library -(check out RAFT's `bitset API documentation `). When calling a search function of an ANN index, the -bitset length should match the number of vectors present in the database. - -Bitmap -====== - -A bitmap is based on the same principle as a bitset, but in two dimensions. This allows users to provide a different bitset for each query -being searched. Check out RAFT's `bitmap API documentation `. - -Examples -======== - -Using a Bitset filter on a CAGRA index --------------------------------------- - -.. code-block:: c++ - - #include - #include - - using namespace cuvs::neighbors; - cagra::index index; - - // ... build index ... - - cagra::search_params search_params; - raft::device_resources res; - raft::device_matrix_view queries = load_queries(); - raft::device_matrix_view neighbors = make_device_matrix_view(n_queries, k); - raft::device_matrix_view distances = make_device_matrix_view(n_queries, k); - - // Load a list of all the samples that will get filtered - std::vector removed_indices_host = get_invalid_indices(); - auto removed_indices_device = - raft::make_device_vector(res, removed_indices_host.size()); - // Copy this list to device - raft::copy(removed_indices_device.data_handle(), removed_indices_host.data(), - removed_indices_host.size(), raft::resource::get_cuda_stream(res)); - - // Create a bitset with the list of samples to filter. - cuvs::core::bitset removed_indices_bitset( - res, removed_indices_device.view(), index.size()); - // Use a `bitset_filter` in the `cagra::search` function call. - auto bitset_filter = - cuvs::neighbors::filtering::bitset_filter(removed_indices_bitset.view()); - cagra::search(res, - search_params, - index, - queries, - neighbors, - distances, - bitset_filter); - - -Using a Bitmap filter on a Brute-force index --------------------------------------------- - -.. code-block:: c++ - - #include - #include - - using namespace cuvs::neighbors; - using indexing_dtype = int64_t; - - // ... build index ... - brute_force::index_params index_params; - brute_force::search_params search_params; - raft::device_resources res; - raft::device_matrix_view dataset = load_dataset(n_vectors, dim); - raft::device_matrix_view queries = load_queries(n_queries, dim); - auto index = brute_force::build(res, index_params, raft::make_const_mdspan(dataset.view())); - - // Load a list of all the samples that will get filtered - std::vector removed_indices_host = get_invalid_indices(); - auto removed_indices_device = - raft::make_device_vector(res, removed_indices_host.size()); - // Copy this list to device - raft::copy(removed_indices_device.data_handle(), removed_indices_host.data(), - removed_indices_host.size(), raft::resource::get_cuda_stream(res)); - - // Create a bitmap with the list of samples to filter. - cuvs::core::bitset removed_indices_bitset( - res, removed_indices_device.view(), n_queries * n_vectors); - cuvs::core::bitmap_view removed_indices_bitmap( - removed_indices_bitset.data(), n_queries, n_vectors); - - // Use a `bitmap_filter` in the `brute_force::search` function call. - auto bitmap_filter = - cuvs::neighbors::filtering::bitmap_filter(removed_indices_bitmap); - - auto neighbors = raft::make_device_matrix_view(n_queries, k); - auto distances = raft::make_device_matrix_view(n_queries, k); - brute_force::search(res, - search_params, - index, - raft::make_const_mdspan(queries.view()), - neighbors.view(), - distances.view(), - bitmap_filter); diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst deleted file mode 100644 index 656bdf32e4..0000000000 --- a/docs/source/getting_started.rst +++ /dev/null @@ -1,124 +0,0 @@ -~~~~~~~~~~~~~~~ -Getting Started -~~~~~~~~~~~~~~~ - -- `New to vector search?`_ - - * :doc:`Primer on vector search ` - - * :doc:`Vector search indexes vs vector databases ` - - * :doc:`Index tuning guide ` - - * :doc:`Comparing vector search index performance ` - -- `Supported indexes`_ - - * :doc:`Vector search index guide ` - -- `Using cuVS APIs`_ - - * :doc:`C API Docs ` - - * :doc:`C++ API Docs ` - - * :doc:`Python API Docs ` - - * :doc:`Rust API Docs ` - - * :doc:`API basics ` - - * :doc:`API interoperability ` - -- `Where to next?`_ - - * `Social media`_ - - * `Blogs`_ - - * `Research`_ - - * `Get involved`_ - -New to vector search? -===================== - -If you are unfamiliar with the basics of vector search or how vector search differs from vector databases, then :doc:`this primer on vector search guide ` should provide some good insight. Another good resource for the uninitiated is our :doc:`vector databases vs vector search ` guide. As outlined in the primer, vector search as used in vector databases is often closer to machine learning than to traditional databases. This means that while traditional databases can often be slow without any performance tuning, they will usually still yield the correct results. Unfortunately, vector search indexes, like other machine learning models, can yield garbage results if not tuned correctly. - -Fortunately, this opens up the whole world of hyperparameter optimization to improve vector search performance and quality. Please see our :doc:`index tuning guide ` for more information. - -When comparing the performance of vector search indexes, it is important that considerations are made with respect to three main dimensions: - -#. Build time -#. Search quality -#. Search performance - -Please see the :doc:`primer on comparing vector search index performance ` for more information on methodologies and how to make a fair apples-to-apples comparison during your evaluations. - -Supported indexes -================= - -cuVS supports many of the standard index types with the list continuing to grow and stay current with the state-of-the-art. Please refer to our :doc:`vector search index guide ` to learn more about each individual index type, when they can be useful on the GPU, the tuning knobs they offer to trade off performance and quality. - -The primary goal of cuVS is to enable speed, scale, and flexibility (in that order)- and one of the important value propositions is to enhance existing software deployments with extensible GPU capabilities to improve pain points while not interrupting parts of the system that work well today with CPU. - - -Using cuVS APIs -=============== - -cuVS is a C++ library at its core, which is wrapped with a C library and exposed further through various different languages. cuVS currently provides APIs and documentation for :doc:`C `, :doc:`C++ `, :doc:`Python `, and :doc:`Rust ` with more languages in the works. our :doc:`API basics ` provides some background and context about the important paradigms and vocabulary types you'll encounter when working with cuVS types. - -Please refer to the :doc:`guide on API interoperability ` for more information on how cuVS can work seamlessly with other libraries like numpy, cupy, tensorflow, and pytorch, even without having to copy device memory. - - -Where to next? -============== - -cuVS is free and open source software, licensed under Apache 2.0 Once you are familiar with and/or have used cuVS, you can access the developer community most easily through `Github `_. Please open Github issues for any bugs, questions or feature requests. - -Social media ------------- - -You can access the RAPIDS community through `Slack `_ , `Stack Overflow `_ and `X `_ - -Blogs ------ - -We frequently publish blogs on GPU-enabled vector search, which can provide great deep dives into various important topics and breakthroughs: - -#. `See all cuVS blogs `_ -#. `Accelerated Vector Search: Approximating with cuVS IVF-Flat `_ -#. Accelerating Vector Search with cuVS IVF-PQ (`Part 1 `_, `Part 2 `_) - -Research --------- - -For the interested reader, many of the accelerated implementations in cuVS are also based on research papers which can provide a lot more background. We also ask you to please cite the corresponding algorithms by referencing them in your own research. - -#. `CAGRA: Highly Parallel Graph Construction and Approximate Nearest Neighbor Search `_ -#. `Top-K Algorithms on GPU: A Comprehensive Study and New Methods `_ -#. `Fast K-NN Graph Construction by GPU Based NN-Descent `_ -#. `cuSLINK: Single-linkage Agglomerative Clustering on the GPU `_ -#. `GPU Semiring Primitives for Sparse Neighborhood Methods `_ -#. `VecFlow: A High-Performance Vector Data Management System for Filtered-Search on GPUs `_ - - -Get involved ------------- - -We always welcome patches for new features and bug fixes. Please read our `contributing guide `_ for more information on contributing patches to cuVS. - - - -.. toctree:: - :hidden: - - choosing_and_configuring_indexes.rst - vector_databases_vs_vector_search.rst - tuning_guide.rst - comparing_indexes.rst - neighbors/neighbors.rst - api_basics.rst - api_interoperability.rst - working_with_ann_indexes.rst - filtering.rst diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index ecf92ffa8e..0000000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,92 +0,0 @@ -cuVS: Vector Search and Clustering on the GPU -============================================= - -Welcome to cuVS, the premier library for GPU-accelerated vector search and clustering! cuVS provides several core building blocks for constructing new algorithms, as well as end-to-end vector search and clustering algorithms for use either standalone or through a growing list of :doc:`integrations `. - -Useful Resources -################ - -.. _cuvs_reference: https://docs.rapids.ai/api/cuvs/stable/ - -- `Example Notebooks `_: Example notebooks -- `Code Examples `_: Self-contained code examples -- `RAPIDS Community `_: Get help, contribute, and collaborate. -- `GitHub repository `_: Download the cuVS source code. -- `Issue tracker `_: Report issues or request features. - - - -What is cuVS? -############# - -cuVS contains state-of-the-art implementations of several algorithms for running approximate and exact nearest neighbors and clustering on the GPU. It can be used directly or through the various databases and other libraries that have integrated it. The primary goal of cuVS is to simplify the use of GPUs for vector similarity search and clustering. - -Vector search is an information retrieval method that has been growing in popularity over the past few years, partly because of the rising importance of multimedia embeddings created from unstructured data and the need to perform semantic search on the embeddings to find items which are semantically similar to each other. - -Vector search is also used in *data mining and machine learning* tasks and comprises an important step in many *clustering* and *visualization* algorithms like `UMAP `_, `t-SNE `_, K-means, and `HDBSCAN `_. - -Finally, faster vector search enables interactions between dense vectors and graphs. Converting a pile of dense vectors into nearest neighbors graphs unlocks the entire world of graph analysis algorithms, such as those found in `GraphBLAS `_ and `cuGraph `_. - -Below are some common use-cases for vector search - -Semantic search -~~~~~~~~~~~~~~~ -- Generative AI & Retrieval augmented generation (RAG) -- Recommender systems -- Computer vision -- Image search -- Text search -- Audio search -- Molecular search -- Model training - - -Data mining -~~~~~~~~~~~ -- Clustering algorithms -- Visualization algorithms -- Sampling algorithms -- Class balancing -- Ensemble methods -- k-NN graph construction - -Why cuVS? -######### - -There are several benefits to using cuVS and GPUs for vector search, including - -1. Fast index build -2. Latency critical and high throughput search -3. Parameter tuning -4. Cost savings -5. Interoperability (build on GPU, deploy on CPU) -6. Multiple language support -7. Building blocks for composing new or accelerating existing algorithms - -In addition to the items above, cuVS shoulders the responsibility of keeping non-trivial accelerated code up to date as new NVIDIA architectures and CUDA versions are released. This provides a delightful development experience, guaranteeing that any libraries, databases, or applications built on top of it will always be receiving the best performance and scale. - -cuVS Technology Stack -##################### - -cuVS is built on top of the RAPIDS RAFT library of high performance machine learning primitives and provides all the necessary routines for vector search and clustering on the GPU. - -.. image:: ../../img/tech_stack.png - :width: 600 - :alt: cuVS is built on top of low-level CUDA libraries and provides many important routines that enable vector search and clustering on the GPU - - - -Contents -######## - -.. toctree:: - :maxdepth: 4 - - build.rst - getting_started.rst - integrations.rst - cuvs_bench/index.rst - api_docs.rst - advanced_topics.rst - contributing.md - developer_guide.md diff --git a/docs/source/integrations.rst b/docs/source/integrations.rst deleted file mode 100644 index 760892a98a..0000000000 --- a/docs/source/integrations.rst +++ /dev/null @@ -1,13 +0,0 @@ -============ -Integrations -============ - -Aside from using cuVS standalone, it can be consumed through a number of sdk and vector database integrations. - -.. toctree:: - :maxdepth: 4 - - integrations/faiss.rst - integrations/milvus.rst - integrations/lucene.rst - integrations/kinetica.rst diff --git a/docs/source/integrations/faiss.rst b/docs/source/integrations/faiss.rst deleted file mode 100644 index 1fc88d921c..0000000000 --- a/docs/source/integrations/faiss.rst +++ /dev/null @@ -1,6 +0,0 @@ -Faiss ------ - -Faiss v1.10.0 and beyond provides a special conda package that enables a cuVS backend for the Flat, IVF-Flat, IVF-PQ and CAGRA indexes on the GPU. Like the classical Faiss GPU indexes, the cuVS backend also enables interoperability between Faiss CPU indexes, allowing an index to be trained on GPU, searched on CPU, and vice versa. - -The cuVS backend can be enabled by setting the appropriate cmake flag while building Faiss from source. A pre-compiled conda package can also be installed. Refer to `Faiss installation guidelines `_ for more information. diff --git a/docs/source/integrations/kinetica.rst b/docs/source/integrations/kinetica.rst deleted file mode 100644 index e74cfe82fd..0000000000 --- a/docs/source/integrations/kinetica.rst +++ /dev/null @@ -1,6 +0,0 @@ -Kinetica --------- - -Starting with release 7.2, Kinetica supports the graph-based the CAGRA algorithm from RAFT. Kinetica will continue to improve its support over coming versions, while also migrating to cuVS as we work to move the vector search algorithms out of RAFT and into cuVS. - -Kinetica currently offers the ability to create a CAGRA index in a SQL `CREATE_TABLE` statement, as outlined in their `vector search indexing docs `_. Kinetica is not open source, but the RAFT indexes can be enabled in the developer edition, which can be installed `here `_. diff --git a/docs/source/integrations/lucene.rst b/docs/source/integrations/lucene.rst deleted file mode 100644 index d20052545b..0000000000 --- a/docs/source/integrations/lucene.rst +++ /dev/null @@ -1,6 +0,0 @@ -Lucene ------- - -An experimental Lucene connector for cuVS enables GPU-accelerated vector search indexes through Lucene. Initial benchmarks are showing that this connector can drastically improve the performance of both indexing and search in Lucene. This connector will continue to be improved over time and any interested developers are encouraged to contribute. - -Install and evaluate the `lucene-cuvs` connector on `Github `_. diff --git a/docs/source/integrations/milvus.rst b/docs/source/integrations/milvus.rst deleted file mode 100644 index 4139cca526..0000000000 --- a/docs/source/integrations/milvus.rst +++ /dev/null @@ -1,8 +0,0 @@ -Milvus ------- - -In version 2.3, Milvus released support for IVF-Flat and IVF-PQ indexes on the GPU through RAFT. Version 2.4 adds support for brute-force and the graph-based CAGRA index on the GPU. Please refer to the `Milvus documentation `_ to install Milvus with GPU support. - -The GPU indexes can be enabled by using the index types prefixed with `GPU_`, as outlined in the `Milvus index build guide `_. - -Milvus will be migrating their GPU support from RAFT to cuVS as we continue to move the vector search algorithms out of RAFT and into cuVS. diff --git a/docs/source/neighbors/all_neighbors.rst b/docs/source/neighbors/all_neighbors.rst deleted file mode 100644 index a70414fe06..0000000000 --- a/docs/source/neighbors/all_neighbors.rst +++ /dev/null @@ -1,71 +0,0 @@ -All-neighbors -============= - -All-neighbors is a specialized algorithm for building approximate all-neighbors k-NN graphs. Unlike traditional nearest neighbor indexes that are designed for searching, all-neighbors focuses on constructing complete k-NN graphs for entire datasets. - -This algorithm is particularly useful for: -- Graph construction for visualization algorithms (UMAP, t-SNE) -- Building connectivity graphs for clustering algorithms -- Creating similarity graphs for graph-based machine learning -- Batch processing of large datasets across multiple GPUs - -All-neighbors supports multiple underlying algorithms: -- **Brute Force**: Exact nearest neighbors computation -- **IVF-PQ**: Approximate nearest neighbors using inverted file with product quantization -- **NN-Descent**: Approximate nearest neighbors using graph-based descent - -The algorithm partitions the dataset into clusters and distributes the work across multiple GPUs when possible, making it suitable for large-scale graph construction tasks. - -[ :doc:`C API <../c_api/neighbors_all_neighbors_c>` | :doc:`C++ API <../cpp_api/neighbors_all_neighbors>` | :doc:`Python API <../python_api/neighbors_all_neighbors>` ] - -Algorithm Overview ------------------- - -All-neighbors works by: - -1. **Partitioning**: Dividing the dataset into `n_clusters` clusters/batches -2. **Assignment**: Assigning each point to `overlap_factor` clusters (must be < n_clusters) -3. **Local Computation**: Building k-NN graphs within each cluster using the specified algorithm -4. **Aggregation**: Combining results from all clusters to form the complete graph - -This approach enables: -- **Scalability**: Work distribution across multiple GPUs -- **Memory Efficiency**: Processing large datasets that don't fit in single GPU memory -- **Flexibility**: Choice of underlying algorithm based on accuracy vs. speed requirements - -Use Cases ---------- - -**Data Mining and Machine Learning** -- Clustering algorithms (K-means, HDBSCAN) -- Visualization algorithms (UMAP, t-SNE) -- Sampling and ensemble methods - -**Graph Construction** -- Building similarity graphs for graph neural networks -- Creating connectivity matrices for spectral clustering -- Constructing neighborhood graphs for manifold learning - -**Large-scale Processing** -- Processing datasets that exceed single GPU memory -- Batch processing for distributed computing environments -- Building graphs for graph databases and analytics - -Parameters ----------- - -- **algo**: Underlying algorithm (brute_force, ivf_pq, nn_descent) -- **overlap_factor**: Number of clusters each point is assigned to -- **n_clusters**: Total number of clusters for work distribution -- **metric**: Distance metric for graph construction -- **algorithm-specific parameters**: IVF-PQ or NN-Descent specific settings - -Performance Characteristics ---------------------------- - -- **Build Time**: Scales with dataset size and chosen algorithm -- **Memory Usage**: Depends on cluster size and overlap factor -- **Accuracy**: Varies by algorithm (brute_force, others) and also according to the number of clusters (n_clusters). n_clusters>1 will result in an approximation. -- **Scalability**: Linear scaling with number of GPUs when n_clusters > 1 - -The algorithm automatically chooses between single-GPU and multi-GPU execution based on the n_clusters parameter and available resources. diff --git a/docs/source/neighbors/bruteforce.rst b/docs/source/neighbors/bruteforce.rst deleted file mode 100644 index 3dc1155073..0000000000 --- a/docs/source/neighbors/bruteforce.rst +++ /dev/null @@ -1,62 +0,0 @@ -Brute-force -=========== - -Brute-force, or flat index, is the most simple index type, as it ultimately boils down to an exhaustive matrix multiplication. - -While it scales with :math:`O(N^2*D)`, brute-force can be a great choice when - -1. exact nearest neighbors are required, and -2. when the number of vectors is relatively small (a few thousand to a few million) - -Brute-force can also be a good choice for heavily filtered queries where other algorithms might struggle returning the expected results. For example, -when filtering out 90%-95% of the vectors from a search, the IVF methods could struggle to return anything at all with smaller number of probes and -graph-based algorithms with limited hash table memory could end up skipping over important unfiltered entries. - -[ :doc:`C API <../c_api/neighbors_bruteforce_c>` | :doc:`C++ API <../cpp_api/neighbors_bruteforce>` | :doc:`Python API <../python_api/neighbors_brute_force>` | :doc:`Rust API <../rust_api/index>` ] - -Filtering considerations ------------------------- - -Because it is exhaustive, brute-force can quickly become the slowest, albeit most accurate form of search. However, even -when the number of vectors in an index are very large, brute-force can still be used to search vectors efficiently with a filter. - -This is especially true for cases where the filter is excluding 90%-99% of the vectors in the index where the partitioning -inherent in other approximate algorithms would simply not include expected vectors in the results. In the case of pre-filtered -brute-force, the computation is inverted so distances are only computed between vectors that pass the filter, significantly reducing -the amount of computation required. - -Configuration parameters ------------------------- - -Build parameters -~~~~~~~~~~~~~~~~ - -None - -Search Parameters -~~~~~~~~~~~~~~~~~ - -None - - -Tuning Considerations ---------------------- - -Brute-force is exact but that doesn't always mean it's deterministic. For example, when there are many nearest neighbors with -the same distances it's possible they might be ordered differently across different runs. This especially becomes apparent in -cases where there are points with the same distance right near the cutoff of `k`, which can cause the final list of neighbors -to differ from ground truth. This is not often a problem in practice and can usually be mitigated by increasing `k`. - - -Memory footprint ----------------- - -:math:`precision` is the number of bytes in each element of each vector (e.g. 32-bit = 4-bytes) - - -Index footprint -~~~~~~~~~~~~~~~ - -Raw vectors: :math:`n\_vectors * n\_dimensions * precision` - -Vector norms (for distances which require them): :math:`n\_vectors * precision` diff --git a/docs/source/neighbors/cagra.rst b/docs/source/neighbors/cagra.rst deleted file mode 100644 index 471f3a915a..0000000000 --- a/docs/source/neighbors/cagra.rst +++ /dev/null @@ -1,276 +0,0 @@ -CAGRA -===== - -CAGRA, or (C)UDA (A)NN (GRA)ph-based, is a graph-based index that is based loosely on the popular navigable small-world graph (NSG) algorithm, but which has been -built from the ground-up specifically for the GPU. CAGRA constructs a flat graph representation by first building a kNN graph -of the training points and then removing redundant paths between neighbors. - -The CAGRA algorithm has two basic steps- -* 1. Construct a kNN graph -* 2. Prune redundant routes from the kNN graph. - -I-force could be used to construct the initial kNN graph. This would yield the most accurate graph but would be very slow and -we find that in practice the kNN graph does not need to be very accurate since the pruning step helps to boost the overall recall of -the index. cuVS provides IVF-PQ and NN-Descent strategies for building the initial kNN graph and these can be selected in index params object during index construction. - -[ :doc:`C API <../c_api/neighbors_cagra_c>` | :doc:`C++ API <../cpp_api/neighbors_cagra>` | :doc:`Python API <../python_api/neighbors_cagra>` | :doc:`Rust API <../rust_api/index>` ] - -Interoperability with HNSW --------------------------- - -cuVS provides the capability to convert a CAGRA graph to an HNSW graph, which enables the GPU to be used only for building the index -while the CPU can be leveraged for search. - -Filtering considerations ------------------------- - -CAGRA supports filtered search and has improved multi-CTA algorithm in branch-25.02 to provide reasonable recall and performance for filtering rate as high as 90% or more. - -To obtain an appropriate recall in filtered search, it is necessary to set search parameters according to the filtering rate, but since it is difficult for users to do this, CAGRA automatically adjusts `itopk_size` internally according to the filtering rate on a heuristic basis. If you want to disable this automatic adjustment, set `filtering_rate`, one of the search parameters, to `0.0`, and `itopk_size` will not be adjusted automatically. - -Configuration parameters ------------------------- - -Build parameters -~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - compression - - None - - For large datasets, the raw vectors can be compressed using product quantization so they can be placed on device. This comes at the cost of lowering recall, though a refinement reranking step can be used to make up the lost recall after search. - * - graph_build_algo - - 'IVF_PQ' - - The graph build algorithm to use for building - * - graph_build_params - - None - - Specify explicit build parameters for the corresponding graph build algorithms - * - graph_degree - - 32 - - The degree of the final CAGRA graph. All vertices in the graph will have this degree. During search, a larger graph degree allows for more exploration of the search space and improves recall but at the expense of searching more vertices. - * - intermediate_graph_degree - - 64 - - The degree of the initial knn graph before it is optimized into the final CAGRA graph. A larger value increases connectivity of the initial graph so that it performs better once pruned. Larger values come at the cost of increased device memory usage and increases the time of initial knn graph construction. - * - guarantee_connectivity - - False - - Uses a degree-constrained minimum spanning tree to guarantee the initial knn graph is connected. This can improve recall on some datasets. - * - attach_data_on_build - - True - - Should the dataset be attached to the index after the index is built? Setting this to `False` can improve memory usage and performance, for example if the graph is being serialized to disk or converted to HNSW right after building it. - -Search parameters -~~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - itopk_size - - 64 - - Number of intermediate search results retained during search. This value needs to be >=k. This is the main knob to tweak search performance. - * - max_iterations - - 0 - - The maximum number of iterations during search. Default is to auto-select. - * - max_queries - - 0 - - Max number of search queries to perform concurrently (batch size). Default is to auto-select. - * - team_size - - 0 - - Number of CUDA threads for calculating each distance. Can be 4, 8, 16, or 32. Default is to auto-select. - * - search_width - - 1 - - Number of vertices to select as the starting point for the search in each iteration. - * - min_iterations - - 0 - - Minimum number of search iterations to perform - -Tuning Considerations ---------------------- - -The 3 hyper-parameters that are most often tuned are `graph_degree`, `intermediate_graph_degree`, and `itopk_size`. - -Memory footprint -================ - -CAGRA builds a nearest-neighbor graph (stored on host) while keeping the original dataset vectors around. During index build, the dataset must reside in device (GPU) memory. After building, the dataset can optionally be detached from the index — for example, when immediately converting the CAGRA graph to a CPU-based format like HNSW for search. - -Baseline Memory Footprint -------------------------- - -The baseline memory footprint after index construction: - -.. math:: - - \text{dataset_size (device)} - \;=\; - \text{number_vectors} \times \text{vector_dimension} \times \text{bytes_per_dimension} - -.. math:: - - \text{graph_size (host)} - \;=\; - \text{number_vectors} \times \text{graph_degree} \times \operatorname{sizeof}\!\big(\mathrm{IdxT}\big) - -Note: The dataset must be in GPU memory during index build, but can be detached afterward if not needed for search. - -**Example** (1,000,000 vectors, dim = 1024, fp32, graph\_degree = 64, IdxT = int32): - -- dataset\_size = 4,096,000,000 B = 3906.25 MB -- graph\_size = 256,000,000 B = 244.14 MB - -Build peak memory usage ------------------------ - -Index build has two phases: (1) construct a knn graph, then (2) optimize it to remove redundant and unnecessary paths. -The initial knn graph can be built with IVF-PQ or nn-descent. IVF-PQ has the additional benefit that it supports out-of-core construction, allowing CAGRA to be trained on datasets larger than available GPU memory. -The steps below are sequential with distinct peak memory consumption. The overall peak memory utilization depends on the configured RMM memory resource. - -knn graph build phase using IVF-PQ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The knn graph can be constructed using the IVF-PQ algorithm, which works in two stages: first, an IVF-PQ index is trained on a subset of vectors to learn cluster centroids; then, the full dataset is queried against this index in batches to find approximate nearest neighbors for each vector. - -**IVF-PQ Build (centroid training)** — uses a training subset to compute cluster centroids and PQ codebooks. - -.. math:: - - \text{IVFPQ_build_peak} - \;=\; - \frac{n_{\text{vectors}}}{\text{train_set_ratio}} \times \text{dim} \times 4 - \;+\; - n_{\text{clusters}} \times \text{dim} \times 4 - \;+\; - \frac{n_{\text{vectors}}}{\text{train_set_ratio}} \times \operatorname{sizeof}(\mathrm{uint32\_t}) - -**Example** (n = 1e6; dim = 1024; n\_clusters = 1024; train\_set\_ratio = 10): 395.01 MB - -**IVF-PQ Search (forms the intermediate graph)** — Constructs the knn graph in batches by querying the IVF-PQ index for the nearest neighbors of all training points. - -.. math:: - - \text{IVFPQ_search_peak} - \;=\; - \text{batch_size} \times \text{dim} \times 4 - \;+\; - \text{batch_size} \times \text{intermediate_degree} \times \operatorname{sizeof}(\mathrm{uint32\_t}) - \;+\; - \text{batch_size} \times \text{intermediate_degree} \times 4 - -**Example** (batch = 1024, dim = 1024, intermediate\_degree = 128): 5.00 MB - -knn graph build phase using NN-DESCENT -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**Peak device memory:** - -.. math:: - - \text{NND_device_peak} - \;=\; - n_\text{vectors} \times (n_\text{dims} \times 2 + 276) - -- Data vectors (transferred to device and stored as fp16): :math:`n_\text{dims} \times 2` bytes per vector -- Small working graph, locks, edge counters: 276 bytes per vector (fixed) -- Additional :math:`4` bytes per vector when using L2 metric (for precomputed norms) - -**Peak host memory:** - -.. math:: - - \text{NND_host_peak} - \;=\; - n_\text{vectors} \times (13 \times \text{intermediate_graph_degree} + 912) - -- Full graph with distances (~1.3x overallocation): :math:`1.3 \times 8 \times \text{intermediate_graph_degree}` bytes per vector -- Bloom filter for sampling: :math:`1.3 \times 2 \times \text{intermediate_graph_degree}` bytes per vector -- 5 sample buffers (degree 32 each): 640 bytes per vector -- Graph update buffer (degree 32): 256 bytes per vector -- Edge counters: 16 bytes per vector - - -Optimize phase -~~~~~~~~~~~~~~ - -Pruning/reordering the intermediate graph; peak scales linearly with intermediate degree. - -.. math:: - - \text{optimize_peak} - \;=\; - n_{\text{vectors}} \times - \Big( 4 + \big(\operatorname{sizeof}(\mathrm{IdxT}) + 1\big)\times \text{intermediate_degree} \Big) - -**Example** (n = 1e6, intermediate\_degree = 128, IdxT = int32): 614.17 MB -Out-of-core CAGRA build consists of IVF-PQ build, IVF-PQ search, CAGRA optimization. Note that these steps are performed sequentially, so they are not additive. - -Overall Build Peak Memory Usage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The overall peak memory footprint on the device is the maximum allocation across each sequential step, since RMM's ``device_memory_resource`` releases memory between steps. - -**Using IVF-PQ:** - -.. math:: - - \text{build_peak} - \;=\; - \text{dataset_size} - \;+\; - \max\!\big(\text{IVFPQ_build_peak},\ \text{IVFPQ_search_peak},\ \text{optimize_peak}\big) - -**Example:** 3906.25 + max(395.01, 5.00, 614.17) = 4520.42 MB - -**Using NN-Descent:** - -.. math:: - - \text{build_peak} - \;=\; - \text{dataset_size}^{*} - \;+\; - \max\!\big(\text{NND_device_peak},\ \text{optimize_peak}\big) - -:math:`\text{dataset_size}^{*}` applies only when the user passes data residing in device memory; NN-Descent internally copies the dataset to the device as fp16, so host-memory inputs do not add this term. - -Search peak memory usage ------------------------- - -CAGRA search requires the dataset and graph to already be resident in GPU memory. When using CAGRA-Q (compressed/quantized), the original dataset can reside in host memory instead. Additionally, temporary workspace memory is needed to store the search results for a batch of queries. -If multiple batches are to be launched concurrently or overlapped, separate results buffers will be needed for each. -The below memory estimate assumes just one batch of queries being run at a time and reusing the buffers. - -.. math:: - - \text{search_memory} - \;=\; - \text{dataset_size} + \text{graph_size} + \text{workspace_size} - -Where ``workspace_size`` is the temporary memory used for query vectors and result storage: - -.. math:: - - \text{query_size} - \;=\; - \text{batch_size} \times \text{dim} \times \operatorname{sizeof}(\mathrm{float}) - -.. math:: - - \text{result_size} - \;=\; - \text{batch_size} \times \text{topk} \times - \big(\operatorname{sizeof}(\mathrm{IdxT}) + \operatorname{sizeof}(\mathrm{float})\big) - -**Example** (dim = 1024, batch\_size = 100, topk = 10, IdxT = int32): - -- query\_size = 409,600 B = 0.39 MB -- result\_size = 8,000 B = 0.0076 MB -- workspace\_size = query\_size + result\_size = 0.40 MB -- Total search memory ≈ 3906.25 + 244.14 + 0.40 = 4150.79 MB diff --git a/docs/source/neighbors/ivfflat.rst b/docs/source/neighbors/ivfflat.rst deleted file mode 100644 index d4c8f03c18..0000000000 --- a/docs/source/neighbors/ivfflat.rst +++ /dev/null @@ -1,115 +0,0 @@ -IVF-Flat -======== - -IVF-Flat is an inverted file index (IVF) algorithm, which in the context of nearest neighbors means that data points are -partitioned into clusters. At search time, brute-force is performed only in a (user-defined) subset of the closest clusters. -In practice, this algorithm can search the index much faster than brute-force and often still maintain an acceptable -recall, though this comes with the drawback that the index itself copies the original training vectors into a memory layout -that is optimized for fast memory reads and adds some additional memory storage overheads. Once the index is trained, -this algorithm no longer requires the original raw training vectors. - -IVF-Flat tends to be a great choice when - -1. like brute-force, there is enough device memory available to fit all of the vectors -in the index, and -2. exact recall is not needed. as with the other index types, the tuning parameters are used to trade-off recall for search latency / throughput. - -[ :doc:`C API <../c_api/neighbors_ivf_flat_c>` | :doc:`C++ API <../cpp_api/neighbors_ivf_flat>` | :doc:`Python API <../python_api/neighbors_ivf_flat>` | :doc:`Rust API <../rust_api/index>` ] - -Filtering considerations ------------------------- - -IVF methods only apply filters to the lists which are probed for each query point. As a result, the results of a filtered query will likely differ significantly from the results of a filtering applid to an exact method like brute-force. For example. imagine you have 3 IVF lists each containing 2 vectors and you perform a query against only the closest 2 lists but you filter out all but 1 element. If that remaining element happens to be in one of the lists which was not proved, it will not be considered at all in the search results. It's important to consider this when using any of the IVF methods in your applications. - - -Configuration parameters ------------------------- - -Build parameters -~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - n_lists - - sqrt(n) - - Number of coarse clusters used to partition the index. A good heuristic for this value is sqrt(n_vectors_in_index) - * - add_data_on_build - - True - - Should the training points be added to the index after the index is built? - * - kmeans_train_iters - - 20 - - Max number of iterations for k-means training before convergence is assumed. Note that convergence could happen before this number of iterations. - * - kmeans_trainset_fraction - - 0.5 - - Fraction of points that should be subsampled from the original dataset to train the k-means clusters. Default is 1/2 the training dataset. This can often be reduced for very large datasets to improve both cluster quality and the build time. - * - adaptive_centers - - false - - Should the existing trained centroids adapt to new points that are added to the index? This provides a trade-off between improving recall at the expense of having to compute new centroids for clusters when new points are added. When points are added in large batches, the performance cost may not be noticeable. - * - conservative_memory_allocation - - false - - To support dynamic indexes, where points are expected to be added later, the individual IVF lists can be imtentionally overallocated up front to reduce the amount and impact of increasing list sizes, which requires allocating more memory and copying the old list to the new, larger, list. - - -Search parameters -~~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - n_probes - - 20 - - Number of closest IVF lists to scan for each query point. - -Tuning Considerations ---------------------- - -Since IVF methods use clustering to establish spatial locality and partition data points into individual lists, there's an inherent -assumption that the number of lists, and thus the max size of the data in the index is known up front. For some use-cases, this -might not matter. For example, most vector databases build many smaller physical approximate nearest neighbors indexes, each from -fixed-size or maximum-sized immutable segments and so the number of lists can be tuned based on the number of vectors in the indexes. - -Empirically, we've found :math:`\sqrt{n\_index\_vectors}` to be a good starting point for the :math:`n\_lists` hyper-parameter. Remember, having more -lists means less points to search within each list, but it could also mean more :math:`n\_probes` are needed at search time to reach an acceptable -recall. - - -Memory footprint ----------------- - -Each cluster is padded to at least 32 vectors (but potentially up to 1024). Assuming uniform random distribution of vectors/list, we would have -:math:`cluster\_overhead = (conservative\_memory\_allocation ? 16 : 512 ) * dim * sizeof_{float}` - -Note that each cluster is allocated as a separate allocation. If we use a `cuda_memory_resource`, that would grab memory in 1 MiB chunks, so on average we might have 0.5 MiB overhead per cluster. If we us 10s of thousands of clusters, it becomes essential to use pool allocator to avoid this overhead. - -:math:`cluster\_overhead = 0.5 MiB` // if we do not use pool allocator - - -Index (device memory): -~~~~~~~~~~~~~~~~~~~~~~ - -.. math:: - - n\_vectors * n\_dimensions * sizeof(T) + - - n\_vectors * sizeof(int_type) + - - n\_clusters * n\_dimensions * sizeof(T) + - - n\_clusters * cluster_overhead` - - -Peak device memory usage for index build: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:math:`workspace = min(1GB, n\_queries * [(n\_lists + 1 + n\_probes * (k + 1)) * sizeof_{float} + n\_probes * k * sizeof_{idx}])` - -:math:`index\_size + workspace` diff --git a/docs/source/neighbors/ivfpq.rst b/docs/source/neighbors/ivfpq.rst deleted file mode 100644 index e243a5b562..0000000000 --- a/docs/source/neighbors/ivfpq.rst +++ /dev/null @@ -1,135 +0,0 @@ -IVF-PQ -====== - -IVF-PQ is an inverted file index (IVF) algorithm, which is an extension to the IVF-Flat algorithm (e.g. data points are first -partitioned into clusters) where product quantization is performed within each cluster in order to shrink the memory footprint -of the index. Product quantization is a lossy compression method and it is capable of storing larger number of vectors -on the GPU by offloading the original vectors to main memory, however higher compression levels often lead to reduced recall. -Often a strategy called refinement reranking is employed to make up for the lost recall by querying the IVF-PQ index for a larger -`k` than desired and performing a reordering and reduction to `k` based on the distances from the unquantized vectors. Unfortunately, -this does mean that the unquantized raw vectors need to be available and often this can be done efficiently using multiple CPU threads. - -[ :doc:`C API <../c_api/neighbors_ivf_pq_c>` | :doc:`C++ API <../cpp_api/neighbors_ivf_pq>` | :doc:`Python API <../python_api/neighbors_ivf_pq>` | :doc:`Rust API <../rust_api/index>` ] - - -Configuration parameters ------------------------- - -Build parameters -~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - n_lists - - sqrt(n) - - Number of coarse clusters used to partition the index. A good heuristic for this value is sqrt(n_vectors_in_index) - * - kmeans_n_iters - - 20 - - The number of iterations when searching for k-means centers - * - kmeans_trainset_fraction - - 0.5 - - The fraction of training data to use for iterative k-means building - * - pq_bits - - 8 - - The bit length of each vector element after compressing with PQ. Possible values are any integer between 4 and 8. - * - pq_dim - - 0 - - The dimensionality of each vector after compressing with PQ. When 0, the dim is set heuristically. - * - codebook_kind - - per_subspace - - How codebooks are created. `per_subspace` trains kmeans on some number of sub-dimensions while `per_cluster` - * - force_random_rotation - - false - - Apply a random rotation matrix on the input data and queries even if `dim % pq_dim == 0` - * - conservative_memory_allocation - - false - - To support dynamic indexes, where points are expected to be added later, the individual IVF lists can be imtentionally overallocated up front to reduce the amount and impact of increasing list sizes, which requires allocating more memory and copying the old list to the new, larger, list. - * - add_data_on_build - - True - - Should the training points be added to the index after the index is built? - * - max_train_points_per_pq_code - - 256 - - The max number of data points to use per PQ code during PQ codebook training. - - -Search parameters -~~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - n_probes - - 20 - - Number of closest IVF lists to scan for each query point. - * - lut_dtype - - cuda_r_32f - - Datatype to store the pq lookup tables. Can also use cuda_r_16f for half-precision and cuda_r_8u for 8-bit precision. Smaller lookup tables can fit into shared memory and significantly improve search times. - * - internal_distance_dtype - - cuda_r_32f - - Storage data type for distance/similarity computed at search time. Can also use cuda_r_16f for half-precision. - * - preferred_smem_carveout - - 1.0 - - Preferred fraction of SM's unified memory / L1 cache to be used as shared memory. Default is 100% - -Tuning Considerations ---------------------- - -IVF-PQ has similar tuning considerations to IVF-flat, though the PQ compression ratio adds an additional variable to trade-off index size for search quality. - -It's important to note that IVF-PQ becomes very lossy very quickly, and so refinement reranking is often needed to get a reasonable recall. This step usually consists of searching initially for more k-neighbors than needed and then reducing the resulting neighborhoods down to k by computing exact distances. This step can be performed efficiently on CPU or GPU and generally has only a marginal impact on search latency. - -Memory footprint ----------------- - -Index (device memory): -~~~~~~~~~~~~~~~~~~~~~~ - -Simple approximate formula: :math:`n\_vectors * (pq\_dim * \frac{pq\_bits}{8} + sizeof_{idx}) + n\_clusters` - -The IVF lists end up being represented by a sparse data structure that stores the pointers to each list, an indices array that contains the indexes of each vector in each list, and an array with the encoded (and interleaved) data for each list. - -IVF list pointers: :math:`n\_clusters * sizeof_{uint32\_t}` - -Indices: :math:`n\_vectors * sizeof_{idx}` - -Encoded data (interleaved): :math:`n\_vectors * pq\_dim * \frac{pq\_bits}{8}` - -Per subspace method: :math:`4 * pq\_dim * pq\_len * 2^{pq\_bits}` - -Per cluster method: :math:`4 * n\_clusters * pq\_len * 2^{pq\_bits}` - -Extras: :math:`n\_clusters * (20 + 8 * dim)` - -Index (host memory): -~~~~~~~~~~~~~~~~~~~~ - -When refinement is used with the dataset on host, the original raw vectors are needed: :math:`n\_vectors * dims * sizeof_{float}` - -Search peak memory usage (device); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Total usage: :math:`index + queries + output\_indices + output\_distances + workspace` - -Workspace size is not trivial, a heuristic controls the batch size to make sure the workspace fits the `raft::resource::get_workspace_free_bytes(res)``. - -Build peak memory usage (device): -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. math:: - - \frac{n\_vectors}{trainset\_ratio * dims * sizeof_{float}} - - + \frac{n\_vectors}{trainset\_ratio * sizeof_{uint32\_t}} - - + n\_clusters * dim * sizeof_{float} - -Note, if there’s not enough space left in the workspace memory resource, IVF-PQ build automatically switches to the managed memory for the training set and labels. diff --git a/docs/source/neighbors/neighbors.rst b/docs/source/neighbors/neighbors.rst deleted file mode 100644 index f66b73f867..0000000000 --- a/docs/source/neighbors/neighbors.rst +++ /dev/null @@ -1,21 +0,0 @@ -Nearest Neighbor -================ - -.. toctree:: - :maxdepth: 3 - :caption: Contents: - - bruteforce.rst - cagra.rst - ivfflat.rst - ivfpq.rst - vamana.rst - all_neighbors.rst - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/source/neighbors/vamana.rst b/docs/source/neighbors/vamana.rst deleted file mode 100644 index 4f5c2eb5f0..0000000000 --- a/docs/source/neighbors/vamana.rst +++ /dev/null @@ -1,75 +0,0 @@ -Vamana -====== - -VAMANA is the underlying graph construction algorithm used to construct indexes for the DiskANN vector search solution. DiskANN and the Vamana algorithm are described in detail in the `published paper `, and a highly optimized `open-source repository ` includes many features for index construction and search. In cuVS, we provide a version of the Vamana algorithm optimized for GPU architectures to accelreate graph construction to build DiskANN idnexes. At a high level, the Vamana algorithm operates as follows: - -* 1. Starting with an empty graph, select a medoid vector from the D-dimension vector dataset and insert it into the graph. -* 2. Iteratively insert batches of dataset vectors into the graph, connecting each inserted vector to neighbors based on a graph traversal. -* 3. For each batch, create reverse edges and prune unnecessary edges. - -There are many algorithmic details that are outlined in the `paper `, and many GPU-specific optimizations are included in this implementation. - -The current implementation of DiskANN in cuVS only includes the 'in-memory' graph construction and a serialization step that writes the index to a file. This index file can be then used by the `open-source DiskANN ` library to perform efficient search. Additional DiskANN functionality, including GPU-accelerated search and 'ssd' index build are planned for future cuVS releases. - -[ :doc:`C++ API <../cpp_api/neighbors_vamana>` ] - -Interoperability with CPU DiskANN ---------------------------------- - -The 'vamana::serialize' API calls writes the index to a file with a format that is compatible with the `open-source DiskANN repositoriy `. This allows cuVS to be used to accelerate index construction while leveraging the efficient CPU-based search currently available. - -Configuration parameters ------------------------- - -Build parameters -~~~~~~~~~~~~~~~~ - -.. list-table:: - :widths: 25 25 50 - :header-rows: 1 - - * - Name - - Default - - Description - * - graph_degree - - 32 - - The maximum degre of the final Vamana graph. The internal representation of the graph includes this many edges for every node, but serialize will compress the graph into a 'CSR' format with, potentially, fewer edges. - * - visited_size - - 64 - - Maximum number of visited nodes saved during each traversal to insert a new node. This corresponds to the 'L' parameter in the paper. - * - vamana_iters - - 1 - - Number of iterations ran to improve the graph. Each iteration involves inserting every vector in the dataset. - * - alpha - - 1.2 - - Alpha parameter that defines how aggressively to prune edges. - * - max_fraction - - 0.06 - - Maximum fraction of the dataset that will be inserted as a single batch. Larger max batch size decreases graph quality but improves speed. - * - batch_base - - 2 - - Base of growth rate of batch sizes. Insertion batch sizes increase exponentially based on this parameter until max_fraction is reached. - * - queue_size - - 127 - - Size of the candidate queue structure used during graph traversal. Must be (2^x)-1 for some x, and must be > visited_size. - -Tuning Considerations ---------------------- - -The 2 hyper-parameters that are most often tuned are `graph_degree` and `visited_size`. The time needed to create a graph increases dramatically when increasing `graph_degree`, in particular. However, larger graphs may be needed to achieve very high recall search, especially for large datasets. - -Memory footprint ----------------- - -Vamana builds a graph that is stored in device memory. However, in order to serialize the index and write it to a file for later use, it must be moved into host memory. If the `include_dataset` parameter is also set, then the dataset must be resident in host memory when calling serialize as well. - -Device memory usage -~~~~~~~~~~~~~~~~~~~ - -The built index represents the graph as fixed degree, storing a total of :math:`graph\_degree * n\_index\_vectors` edges. Graph construction also requires the dataset be in device memory (or it copies it to device during build). In addition, device memory is used during construction to sort and create the reverse edges. Thus, the amount of device memory needed depends on the dataset itself, but it is bounded by a maximum sum of: - -- vector dataset: :math:`n\_index\_vectors * n\_dims * sizeof(T)` -- output graph: :math:`graph\_degree * n\_index\_vectors * sizeof(IdxT)` -- scratch memory: :math:`n\_index\_vectors * max\_fraction * (2 + graph\_degree) * sizeof(IdxT)` - -Reduction in scratch device memory requirements are planned for upcoming releases of cuVS. diff --git a/docs/source/python_api.rst b/docs/source/python_api.rst deleted file mode 100644 index 4c8fc47820..0000000000 --- a/docs/source/python_api.rst +++ /dev/null @@ -1,13 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~ -Python API Documentation -~~~~~~~~~~~~~~~~~~~~~~~~ - -.. _api: - -.. toctree:: - :maxdepth: 4 - - python_api/cluster.rst - python_api/distance.rst - python_api/neighbors.rst - python_api/preprocessing.rst diff --git a/docs/source/python_api/cluster.rst b/docs/source/python_api/cluster.rst deleted file mode 100644 index b5c0ab957c..0000000000 --- a/docs/source/python_api/cluster.rst +++ /dev/null @@ -1,12 +0,0 @@ -Cluster -======== - -.. role:: py(code) - :language: python - :class: highlight - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - cluster_kmeans.rst diff --git a/docs/source/python_api/cluster_kmeans.rst b/docs/source/python_api/cluster_kmeans.rst deleted file mode 100644 index 8fda17f80d..0000000000 --- a/docs/source/python_api/cluster_kmeans.rst +++ /dev/null @@ -1,27 +0,0 @@ -K-Means -======= - -.. role:: py(code) - :language: python - :class: highlight - -K-Means Parameters -################## - -.. autoclass:: cuvs.cluster.kmeans.KMeansParams - :members: - -K-Means Fit -########### - -.. autofunction:: cuvs.cluster.kmeans.fit - -K-Means Predict -############### - -.. autofunction:: cuvs.cluster.kmeans.predict - -K-Means Cluster Cost -#################### - -.. autofunction:: cuvs.cluster.kmeans.cluster_cost diff --git a/docs/source/python_api/distance.rst b/docs/source/python_api/distance.rst deleted file mode 100644 index debd82953c..0000000000 --- a/docs/source/python_api/distance.rst +++ /dev/null @@ -1,12 +0,0 @@ -Distance -======== - -.. role:: py(code) - :language: python - :class: highlight - - -Pairwise Distance -################# - -.. autofunction:: cuvs.distance.pairwise_distance diff --git a/docs/source/python_api/neighbors.rst b/docs/source/python_api/neighbors.rst deleted file mode 100644 index a9914fa44f..0000000000 --- a/docs/source/python_api/neighbors.rst +++ /dev/null @@ -1,19 +0,0 @@ -Nearest Neighbors -================= - -.. role:: py(code) - :language: python - :class: highlight - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - neighbors_all_neighbors.rst - neighbors_brute_force.rst - neighbors_cagra.rst - neighbors_hnsw.rst - neighbors_ivf_flat.rst - neighbors_ivf_pq.rst - neighbors_multi_gpu.rst - neighbors_nn_decent.rst diff --git a/docs/source/python_api/neighbors_all_neighbors.rst b/docs/source/python_api/neighbors_all_neighbors.rst deleted file mode 100644 index 89ba0f8020..0000000000 --- a/docs/source/python_api/neighbors_all_neighbors.rst +++ /dev/null @@ -1,19 +0,0 @@ -All-Neighbors -============= - -.. role:: py(code) - :language: python - :class: highlight - -All-Neighbors allows building an approximate all-neighbors knn graph. Given a full dataset, it finds nearest neighbors for all the training vectors in the dataset. - -Build Parameters -################ - -.. autoclass:: cuvs.neighbors.all_neighbors.AllNeighborsParams - :members: - -Build -##### - -.. autofunction:: cuvs.neighbors.all_neighbors.build diff --git a/docs/source/python_api/neighbors_brute_force.rst b/docs/source/python_api/neighbors_brute_force.rst deleted file mode 100644 index d756a6c802..0000000000 --- a/docs/source/python_api/neighbors_brute_force.rst +++ /dev/null @@ -1,32 +0,0 @@ -Brute Force KNN -=============== - -.. role:: py(code) - :language: python - :class: highlight - -Index -##### - -.. autoclass:: cuvs.neighbors.brute_force.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.brute_force.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.brute_force.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.brute_force.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.brute_force.load diff --git a/docs/source/python_api/neighbors_cagra.rst b/docs/source/python_api/neighbors_cagra.rst deleted file mode 100644 index 42647914f2..0000000000 --- a/docs/source/python_api/neighbors_cagra.rst +++ /dev/null @@ -1,51 +0,0 @@ -CAGRA -===== - -CAGRA is a graph-based nearest neighbors algorithm that was built from the ground up for GPU acceleration. CAGRA demonstrates state-of-the art index build and query performance for both small- and large-batch sized search. - -.. role:: py(code) - :language: python - :class: highlight - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.cagra.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.cagra.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.cagra.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.cagra.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.cagra.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.cagra.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.cagra.load - -Index extend -############ - -.. autofunction:: cuvs.neighbors.cagra.extend diff --git a/docs/source/python_api/neighbors_hnsw.rst b/docs/source/python_api/neighbors_hnsw.rst deleted file mode 100644 index 40f3a1de7e..0000000000 --- a/docs/source/python_api/neighbors_hnsw.rst +++ /dev/null @@ -1,45 +0,0 @@ -HNSW -==== - -This is a wrapper for hnswlib, to load a CAGRA index as an immutable HNSW index. The loaded HNSW index is only compatible in cuVS, and can be searched using wrapper functions. - -.. role:: py(code) - :language: python - :class: highlight - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.hnsw.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.hnsw.Index - :members: - -Index Conversion -################ - -.. autofunction:: cuvs.neighbors.hnsw.from_cagra - -Index search -############ - -.. autofunction:: cuvs.neighbors.hnsw.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.hnsw.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.hnsw.load - -Index extend -############ - -.. autofunction:: cuvs.neighbors.hnsw.extend diff --git a/docs/source/python_api/neighbors_ivf_flat.rst b/docs/source/python_api/neighbors_ivf_flat.rst deleted file mode 100644 index d0846b0d67..0000000000 --- a/docs/source/python_api/neighbors_ivf_flat.rst +++ /dev/null @@ -1,49 +0,0 @@ -IVF-Flat -======== - -.. role:: py(code) - :language: python - :class: highlight - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.ivf_flat.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.ivf_flat.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.ivf_flat.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.ivf_flat.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.ivf_flat.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.ivf_flat.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.ivf_flat.load - -Index extend -############ - -.. autofunction:: cuvs.neighbors.ivf_flat.extend diff --git a/docs/source/python_api/neighbors_ivf_pq.rst b/docs/source/python_api/neighbors_ivf_pq.rst deleted file mode 100644 index ec4cfdff6a..0000000000 --- a/docs/source/python_api/neighbors_ivf_pq.rst +++ /dev/null @@ -1,49 +0,0 @@ -IVF-PQ -====== - -.. role:: py(code) - :language: python - :class: highlight - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.ivf_pq.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.ivf_pq.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.ivf_pq.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.ivf_pq.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.ivf_pq.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.ivf_pq.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.ivf_pq.load - -Index extend -############ - -.. autofunction:: cuvs.neighbors.ivf_pq.extend diff --git a/docs/source/python_api/neighbors_mg_cagra.rst b/docs/source/python_api/neighbors_mg_cagra.rst deleted file mode 100644 index 763e0e2157..0000000000 --- a/docs/source/python_api/neighbors_mg_cagra.rst +++ /dev/null @@ -1,55 +0,0 @@ -Multi-GPU CAGRA -=============== - -Multi-GPU CAGRA extends the graph-based CAGRA algorithm to work across multiple GPUs, providing improved scalability and performance for large-scale vector search. It supports both replicated and sharded distribution modes. - -.. role:: py(code) - :language: python - :class: highlight - -.. note:: - **IMPORTANT**: Multi-GPU CAGRA requires all data (datasets, queries, output arrays) to be in host memory (CPU). - If using CuPy/device arrays, transfer to host with ``array.get()`` or ``cp.asnumpy(array)`` before use. - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.mg.cagra.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.mg.cagra.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.mg.cagra.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.mg.cagra.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.mg.cagra.search - -Index save -########## - -.. autofunction:: cuvs.neighbors.mg.cagra.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.mg.cagra.load - -Index distribute -################ - -.. autofunction:: cuvs.neighbors.mg.cagra.distribute diff --git a/docs/source/python_api/neighbors_mg_ivf_flat.rst b/docs/source/python_api/neighbors_mg_ivf_flat.rst deleted file mode 100644 index 68eea86fec..0000000000 --- a/docs/source/python_api/neighbors_mg_ivf_flat.rst +++ /dev/null @@ -1,60 +0,0 @@ -Multi-GPU IVF-Flat -================== - -Multi-GPU IVF-Flat extends the IVF-Flat algorithm to work across multiple GPUs, providing improved scalability and performance for large-scale vector search. It supports both replicated and sharded distribution modes. - -.. role:: py(code) - :language: python - :class: highlight - -.. note:: - **IMPORTANT**: Multi-GPU IVF-Flat requires all data (datasets, queries, output arrays) to be in host memory (CPU). - If using CuPy/device arrays, transfer to host with ``array.get()`` or ``cp.asnumpy(array)`` before use. - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.mg.ivf_flat.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.mg.ivf_flat.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.mg.ivf_flat.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.search - -Index extend -############ - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.extend - -Index save -########## - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.load - -Index distribute -################ - -.. autofunction:: cuvs.neighbors.mg.ivf_flat.distribute diff --git a/docs/source/python_api/neighbors_mg_ivf_pq.rst b/docs/source/python_api/neighbors_mg_ivf_pq.rst deleted file mode 100644 index 8343d59753..0000000000 --- a/docs/source/python_api/neighbors_mg_ivf_pq.rst +++ /dev/null @@ -1,60 +0,0 @@ -Multi-GPU IVF-PQ -================ - -Multi-GPU IVF-PQ extends the IVF-PQ (Inverted File with Product Quantization) algorithm to work across multiple GPUs, providing improved scalability and performance for large-scale vector search. It supports both replicated and sharded distribution modes. - -.. role:: py(code) - :language: python - :class: highlight - -.. note:: - **IMPORTANT**: Multi-GPU IVF-PQ requires all data (datasets, queries, output arrays) to be in host memory (CPU). - If using CuPy/device arrays, transfer to host with ``array.get()`` or ``cp.asnumpy(array)`` before use. - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.mg.ivf_pq.IndexParams - :members: - -Index search parameters -####################### - -.. autoclass:: cuvs.neighbors.mg.ivf_pq.SearchParams - :members: - -Index -##### - -.. autoclass:: cuvs.neighbors.mg.ivf_pq.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.build - -Index search -############ - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.search - -Index extend -############ - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.extend - -Index save -########## - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.save - -Index load -########## - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.load - -Index distribute -################ - -.. autofunction:: cuvs.neighbors.mg.ivf_pq.distribute diff --git a/docs/source/python_api/neighbors_multi_gpu.rst b/docs/source/python_api/neighbors_multi_gpu.rst deleted file mode 100644 index bb3a5a07ed..0000000000 --- a/docs/source/python_api/neighbors_multi_gpu.rst +++ /dev/null @@ -1,118 +0,0 @@ -Multi-GPU Nearest Neighbors -=========================== - -Multi-GPU support in cuVS enables scaling ANN (Approximate Nearest Neighbors) algorithms across multiple GPUs on a single node, providing improved performance and the ability to handle larger datasets. - -.. role:: py(code) - :language: python - :class: highlight - -Overview --------- - -The multi-GPU implementations extend the single-GPU algorithms to work across multiple GPUs using two main distribution strategies: - -- **Replicated Mode**: The entire index is replicated across all GPUs. This mode provides higher query throughput by distributing queries across GPUs while maintaining the full index on each GPU. - -- **Sharded Mode**: The index is partitioned (sharded) across GPUs. This mode allows handling larger datasets that don't fit on a single GPU by distributing the data across multiple GPUs. - -Important Notes ---------------- - -.. warning:: - **Memory Requirements**: Multi-GPU algorithms require all data to be in host memory (CPU). This is different from single-GPU algorithms that typically work with device memory. - -.. note:: - **Supported Algorithms**: Currently, multi-GPU support is available for: - - - CAGRA (Graph-based ANN) - - IVF-Flat (Inverted File with Flat storage) - - IVF-PQ (Inverted File with Product Quantization) - - All-neighbors (multi-GPU is built into its unified API via ``MultiGpuResources``) - -Configuration Options ---------------------- - -Distribution Modes -^^^^^^^^^^^^^^^^^^ - -- **Replicated Mode** - - In replicated mode, the complete index is stored on each GPU. This approach: - - - Maximizes query throughput by processing queries in parallel across all GPUs - - Requires each GPU to have enough memory to store the entire index - - Is ideal for scenarios where query throughput is more important than index size limitations - -- **Sharded Mode** - - In sharded mode, the index is distributed across GPUs. This approach: - - - Enables handling of larger datasets by partitioning across GPUs - - Requires coordination between GPUs during search operations - - Is ideal for scenarios where the dataset is too large for a single GPU - -Search Modes -^^^^^^^^^^^^ - -- **Load Balancer** - - Divides each query across multiple GPUs, distributing workload efficiently to maximize performance and throughput. - -- **Round Robin** - - Distributes queries evenly across GPUs in a rotating sequence, ensuring balanced workload allocation. This mode is best suited for frequent, small-scale search operations. - -Merge Modes -^^^^^^^^^^^ - -- **Merge on Root Rank** - - Results from all GPUs are collected and merged on the root rank (typically GPU 0). - -- **Tree Merge** - - Results are merged in a tree-like fashion across GPUs to reduce communication overhead. - -Usage Examples --------------- - -Basic Multi-GPU Usage -^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - import numpy as np - from cuvs.neighbors import mg_cagra - - # Create dataset in host memory - n_samples = 100000 - n_features = 128 - dataset = np.random.random_sample((n_samples, n_features), dtype=np.float32) - - # Build multi-GPU index - build_params = mg_cagra.IndexParams( - distribution_mode="sharded", - metric="sqeuclidean" - ) - index = mg_cagra.build(build_params, dataset) - - # Search with multi-GPU - queries = np.random.random_sample((1000, n_features), dtype=np.float32) - search_params = mg_cagra.SearchParams( - search_mode="load_balancer", - merge_mode="merge_on_root_rank" - ) - distances, neighbors = mg_cagra.search(search_params, index, queries, k=10) - -Algorithm-Specific Documentation --------------------------------- - -.. toctree:: - :maxdepth: 2 - :caption: Multi-GPU Algorithms: - - neighbors_all_neighbors.rst - neighbors_mg_cagra.rst - neighbors_mg_ivf_flat.rst - neighbors_mg_ivf_pq.rst diff --git a/docs/source/python_api/neighbors_nn_decent.rst b/docs/source/python_api/neighbors_nn_decent.rst deleted file mode 100644 index 01e9e196c9..0000000000 --- a/docs/source/python_api/neighbors_nn_decent.rst +++ /dev/null @@ -1,24 +0,0 @@ -NN-Descent -========== - -.. role:: py(code) - :language: python - :class: highlight - -Index build parameters -###################### - -.. autoclass:: cuvs.neighbors.nn_descent.IndexParams - :members: - - -Index -##### - -.. autoclass:: cuvs.neighbors.nn_descent.Index - :members: - -Index build -########### - -.. autofunction:: cuvs.neighbors.nn_descent.build diff --git a/docs/source/python_api/preprocessing.rst b/docs/source/python_api/preprocessing.rst deleted file mode 100644 index bbf1337710..0000000000 --- a/docs/source/python_api/preprocessing.rst +++ /dev/null @@ -1,55 +0,0 @@ -Preprocessing -============= - -.. role:: py(code) - :language: python - :class: highlight - -PCA (Principal Component Analysis) -################################### - -.. autoclass:: cuvs.preprocessing.pca.Params - :members: - -.. autofunction:: cuvs.preprocessing.pca.fit - -.. autofunction:: cuvs.preprocessing.pca.fit_transform - -.. autofunction:: cuvs.preprocessing.pca.transform - -.. autofunction:: cuvs.preprocessing.pca.inverse_transform - -Binary Quantizer -################ - -.. autofunction:: cuvs.preprocessing.quantize.binary.transform - -Product Quantizer -################# - -.. autoclass:: cuvs.preprocessing.quantize.pq.Quantizer - :members: - -.. autoclass:: cuvs.preprocessing.quantize.pq.QuantizerParams - :members: - -.. autofunction:: cuvs.preprocessing.quantize.pq.build - -.. autofunction:: cuvs.preprocessing.quantize.pq.transform - -.. autofunction:: cuvs.preprocessing.quantize.pq.inverse_transform - -Scalar Quantizer -################ - -.. autoclass:: cuvs.preprocessing.quantize.scalar.Quantizer - :members: - -.. autoclass:: cuvs.preprocessing.quantize.scalar.QuantizerParams - :members: - -.. autofunction:: cuvs.preprocessing.quantize.scalar.train - -.. autofunction:: cuvs.preprocessing.quantize.scalar.transform - -.. autofunction:: cuvs.preprocessing.quantize.scalar.inverse_transform diff --git a/docs/source/rust_api/index.rst b/docs/source/rust_api/index.rst deleted file mode 100644 index f79d04fdf8..0000000000 --- a/docs/source/rust_api/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~ -Rust API Documentation -~~~~~~~~~~~~~~~~~~~~~~ - -.. raw:: html - - - - - diff --git a/docs/source/sphinxext/github_link.py b/docs/source/sphinxext/github_link.py deleted file mode 100644 index 1ee5f610b5..0000000000 --- a/docs/source/sphinxext/github_link.py +++ /dev/null @@ -1,154 +0,0 @@ -# This contains code with copyright by the scikit-learn project, subject to the -# license in /thirdparty/LICENSES/LICENSE.scikit_learn -# -# SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION. -# SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause -# - -import inspect -import os -import re -import subprocess -import sys -from operator import attrgetter - -orig = inspect.isfunction - - -# See https://opendreamkit.org/2017/06/09/CythonSphinx/ -def isfunction(obj): - orig_val = orig(obj) - - new_val = hasattr(type(obj), "__code__") - - if orig_val != new_val: - return new_val - - return orig_val - - -inspect.isfunction = isfunction - -REVISION_CMD = "git rev-parse --short HEAD" - -source_regex = re.compile( - r"^File: (.*?) \(starting at line ([0-9]*?)\)$", re.MULTILINE -) - - -def _get_git_revision(): - try: - revision = subprocess.check_output(REVISION_CMD.split()).strip() - except (subprocess.CalledProcessError, OSError): - print("Failed to execute git to get revision") - return None - return revision.decode("utf-8") - - -def _linkcode_resolve(domain, info, package, url_fmt, revision): - """Determine a link to online source for a class/method/function - - This is called by sphinx.ext.linkcode - - An example with a long-untouched module that everyone has - >>> _linkcode_resolve('py', {'module': 'tty', - ... 'fullname': 'setraw'}, - ... package='tty', - ... url_fmt='http://hg.python.org/cpython/file/' - ... '{revision}/Lib/{package}/{path}#L{lineno}', - ... revision='xxxx') - 'http://hg.python.org/cpython/file/xxxx/Lib/tty/tty.py#L18' - """ - - if revision is None: - return - if domain not in ("py", "pyx"): - return - if not info.get("module") or not info.get("fullname"): - return - - class_name = info["fullname"].split(".")[0] - module = __import__(info["module"], fromlist=[class_name]) - obj = attrgetter(info["fullname"])(module) - - # Unwrap the object to get the correct source - # file in case that is wrapped by a decorator - obj = inspect.unwrap(obj) - - fn: str = None - lineno: str = None - - try: - fn = inspect.getsourcefile(obj) - except Exception: - fn = None - if not fn: - try: - fn = inspect.getsourcefile(sys.modules[obj.__module__]) - except Exception: - fn = None - - if not fn: - # Possibly Cython code. Search docstring for source - m = source_regex.search(obj.__doc__) - - if m is not None: - source_file = m.group(1) - lineno = m.group(2) - - # fn is expected to be the absolute path. - fn = os.path.relpath(source_file, start=package) - print( - "{}:{}".format( - os.path.abspath(os.path.join("..", "python", "cuvs", fn)), - lineno, - ) - ) - else: - return - else: - if fn.endswith(".pyx"): - sp_path = next( - x for x in sys.path if re.match(".*site-packages$", x) - ) - fn = fn.replace("/opt/conda/conda-bld/work/python/cuvs", sp_path) - - # Convert to relative from module root - fn = os.path.relpath( - fn, start=os.path.dirname(__import__(package).__file__) - ) - - # Get the line number if we need it. (Can work without it) - if lineno is None: - try: - lineno = inspect.getsourcelines(obj)[1] - except Exception: - # Can happen if its a cyfunction. See if it has `__code__` - if hasattr(obj, "__code__"): - lineno = obj.__code__.co_firstlineno - else: - lineno = "" - return url_fmt.format( - revision=revision, package=package, path=fn, lineno=lineno - ) - - -def make_linkcode_resolve(package, url_fmt): - """Returns a linkcode_resolve function for the given URL format - - revision is a git commit reference (hash or name) - - package is the name of the root module of the package - - url_fmt is along the lines of ('https://github.com/USER/PROJECT/' - 'blob/{revision}/{package}/' - '{path}#L{lineno}') - """ - revision = _get_git_revision() - - def linkcode_resolve(domain, info): - return _linkcode_resolve( - domain, info, revision=revision, package=package, url_fmt=url_fmt - ) - - return linkcode_resolve diff --git a/docs/source/tuning_guide.rst b/docs/source/tuning_guide.rst deleted file mode 100644 index fd54fc42ae..0000000000 --- a/docs/source/tuning_guide.rst +++ /dev/null @@ -1,56 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~ -Automated tuning Guide -~~~~~~~~~~~~~~~~~~~~~~ - -Introduction -============ - -A Method for tuning and evaluating Vector Search Indexes At Scale in Locally Indexed Vector Databases. For more information on the differences between locally and globally indexed vector databases, please see :doc:`this guide `. The goal of this guide is to give users a scalable and effective approach for tuning a vector search index, no matter how large. Evaluation of a vector search index “model” that measures recall in proportion to build time so that it penalizes the recall when the build time is really high (should ultimately optimize for finding a lower build time and higher recall). - -For more information on the various different types of vector search indexes, please see our :doc:`guide to choosing vector search indexes ` - -Why automated tuning? -===================== - -As much as 75% of users have told us they will not be able to tune a vector database beyond one or two simple knobs and we suggest that an ideal “knob” would be to balance training time and search time with search quality. The more time, the higher the quality, and the more needed to find an acceptable search performance. Even the 25% of users that want to tune are still asking for simple tools for doing so. These users also ask for some simple guidelines for setting tuning parameters, like :doc:`this guide `. - -Since vector search indexes are more closely related to machine learning models than traditional databases indexes, one option for easing the parameter tuning burden is to use hyper-parameter optimization tools like `Ray Tune `_ and `Optuna `_. to verify this. - -How to tune? -============ - -But how would this work when we have an index that's massively large- like 1TB? - -One benefit to locally indexed vector databases is that they often scale by breaking the larger set of vectors down into a smaller set by uniformly random subsampling and training smaller vector search index models on the sub-samples. Most often, the same set of tuning parameters are applied to all of the smaller sub-index models, rather than trying to set them individually for each one. During search, the query vectors are often sent to all of the sub-indexes and the resulting neighbors list reduced down to `k` based on the closest distances (or similarities). - -Because many databases use this sub-sampling trick, it's possible to perform an automated parameter tuning on the larger index just by randomly sampling some number of vectors from it, splitting them into disjoint train/test/eval datasets, computing ground truth with brute-force, and then performing a hyper-parameter optimization on it. This procedure can also be repeated multiple times to simulate a monte-carlo cross validation. - -GPUs are naturally great at performing massively parallel tasks, especially when they are largely independent tasks, such as training and evaluating models with different hyper-parameter settings in parallel. Hyper-parameter optimization also lends itself well to distributed processing, such as multi-node multi-GPU operation. - -Steps to achieve automated tuning -================================= - -More formally, an automated parameter tuning workflow with monte-carlo cross-validation looks something like this: - -#. Ingest a large dataset into the vector database of your choice - -#. Choose an index size based on number of vectors. This should usually align with the average number of vectors the database will end up putting in a single ANN sub-index model. - -#. Uniformly random sample the number of vectors specified above from the database for a training set. This is often accomplished by generating some number of random (unique) numbers up to the dataset size. - -#. Uniformly sample some number of vectors for a test set and do this again for an evaluation set. 1-10% of the vectors in the training set. - -#. Use the test set to compute ground truth on the vectors from prior step against all vectors in the training set. - -#. Start the HPO tuning process for the training set, using the test vectors for the query set. It's important to make sure your HPO is multi-objective and optimizes for: a) low build time, b) high throughput or low latency search (depending on needs), and c) acceptable recall. - -#. Use the evaluation dataset to test that the optimal hyper-parameters generalize to unseen points that were not used in the optimization process. - -#. Optionally, the above steps multiple times on different uniform sub-samplings. Optimal parameters can then be combined over the multiple monte-carlo optimization iterations. For example, many hyper-parameters can simply be averaged but care might need to be taken for other parameters. - -#. Create a new index in the database using the ideal params from above that meet the target constraints (e.g. build vs search vs quality) - -Conclusion -========== - -By the end of this process, you should have a set of parameters that meet your target constraints while demonstrating how well the optimal hyper-parameters generalize across the dataset. The major benefit to this approach is that it breaks a potentially unbounded dataset size down into manageable chunks and accelerates tuning on those chunks. We see this process as a major value add for vector search on the GPU. diff --git a/docs/source/vector_databases_vs_vector_search.rst b/docs/source/vector_databases_vs_vector_search.rst deleted file mode 100644 index 5c43ee5508..0000000000 --- a/docs/source/vector_databases_vs_vector_search.rst +++ /dev/null @@ -1,57 +0,0 @@ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Vector search indexes vs vector databases -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This guide provides information on the differences between vector search indexes and fully-fledged vector databases. For more information on selecting and configuring vector search indexes, please refer to our :doc:`guide on choosing and configuring indexes ` - -One of the primary differences between vector database indexes and traditional database indexes is that vector search often uses approximations to trade-off accuracy of the results for speed. Because of this, while many mature databases offer mechanisms to tune their indexes and achieve better performance, vector database indexes can return completely garbage results if they aren’t tuned for a reasonable level of search quality in addition to performance tuning. This is because vector database indexes are more closely related to machine learning models than they are to traditional database indexes. - -What are the differences between vector databases and vector search indexes? -============================================================================ - -Vector search in and of itself refers to the objective of finding the closest vectors in an index around a given set of query vectors. At the lowest level, vector search indexes are just machine learning models, which have a build, search, and recall performance that can be traded off, depending on the algorithm and various hyper-parameters. - -Vector search indexes alone are considered building blocks that enable, but are not considered by themselves to be, a fully-fledged vector database. Vector databases provide more production-level features that often use vector search algorithms in concert with other popular database design techniques to add important capabilities like durability, fault tolerance, vertical scalability, partition tolerance, and horizontal scalability. - -In the world of vector databases, there are special purpose-built databases that focus primarily on vector search but might also provide some small capability of more general-purpose databases, like being able to perform a hybrid search across both vectors and metadata. Many general-purpose databases, both relational and nosql / document databases for example, are beginning to add first-class vector types also. - -So what does all this mean to you? Sometimes a simple standalone vector search index is enough. Usually they can be trained and serialized to a file for later use, and often provide a capability to filter out specific vectors during search. Sometimes they even provide a mechanism to scale up to utilize multiple GPUs, for example, but they generally stop there- and suggest either using your own distributed system (like Spark or Dask) or a fully-fledged vector database to scale out. - -FAISS and cuVS are examples of standalone vector search libraries, which again are more closely related to machine learning libraries than to fully-fledged databases. Milvus is an example of a special-purpose vector database and Elastic, MongoDB, and OpenSearch are examples of general-purpose databases that have added vector search capabilities. - -How is vector search used by vector databases? -============================================== - -Within the context of vector databases, there are two primary ways in which vector search indexes are used and it’s important to understand which you are working with because it can have an effect on the behavior of the parameters with respect to the data. - -Many vector search algorithms improve scalability while reducing the number of distances by partitioning the vector space into smaller pieces, often through the use of clustering, hashing, trees, and other techniques. Another popular technique is to reduce the width or dimensionality of the space in order to decrease the cost of computing each distance. In contrast, databases often partition the data, but may only do so to improve things like io performance, partition tolerance, or scale, without regards to the underlying data distributions which are ultimately going to be used for vector search. - -This leads us to two core architectural designs that we encounter in vector databases: - -Locally partitioned vector search indexes ------------------------------------------ - -Most databases follow this design, and vectors are often first written to a write-ahead log for durability. After some number of vectors are written, the write-ahead logs become immutable and may be merged with other write-ahead logs before eventually being converted to a new vector search index. - -The search is generally done over each locally partitioned index and the results combined. When setting hyperparameters, only the local vector search indexes need to be considered, though the same hyperparameters are going to be used across all of the local partitions. So, for example, if you’ve ingested 100M vectors but each partition only contains about 10M vectors, the size of the index only needs to consider its local 10M vectors. Details like number of vectors in the index are important, for example, when setting the number of clusters in an IVF-based (inverted file index) method, as I’ll cover below. - - -Globally partitioned vector search indexes ------------------------------------------- - -Some special-purpose vector databases follow this design, such as Yahoo’s Vespa and Google’s Spanner. A global index is trained to partition the entire database’s vectors up front as soon as there are enough vectors to do so (usually these databases are at a large enough scale that a significant number of vectors are bootstrapped initially and so it avoids the cold start problem). Ingested vectors are first run through the global index (clustering, for example, but tree- and graph-based methods have also been used) to determine which partition they belong to and the vectors are then (sent to, and) written directly to that partition. The individual partitions can contain a graph, tree, or a simple IVF list. These types of indexes have been able to scale to hundreds of billions to trillions of vectors, and since the partitions are themselves often implicitly based on neighborhoods, rather than being based on uniformly random distributed vectors like the locally partitioned architectures, the partitions can be grouped together or intentionally separated to support localized searches or load balancing, depending upon the needs of the system. - -The challenge when setting hyper-parameters for globally partitioned indexes is that they need to account for the entire set of vectors, and thus the hyperparameters of the global index generally account for all of the vectors in the database, rather than any local partition. - -Of course, the two approaches outlined above can also be used together (e.g. training a global “coarse” index and then creating localized vector search indexes within each of the global indexes) but to my knowledge, no such architecture has implemented this pattern. - -A challenge with GPUs in vector databases today is that the resulting vector indexes are expected to fit into the memory of available GPUs for fast search. That is to say, there doesn’t exist today an efficient mechanism for offloading or swapping GPU indexes so they can be cached from disk or host memory, for example. We are working on mechanisms to do this, and to also utilize technologies like GPUDirect Storage and GPUDirect RDMA to improve the IO performance further. - -Tuning and hyperparameter optimization -====================================== - -Unfortunately, for large datasets, doing a hyper-parameter optimization on the whole dataset is not always feasible and this is actually where the locally partitioned vector search indexes have an advantage because you can think of each smaller segment of the larger index as a uniform random sample of the total vectors in the dataset. This means that it is possible to perform a hyperparameter optimization on the smaller subsets and find reasonably acceptable parameters that should generalize fairly well to the entire dataset. Generally this hyperparameter optimization will require computing a ground truth on the subset with an exact method like brute-force and then using it to evaluate several searches on randomly sampled vectors. - -Full hyper-parameter optimization may also not always be necessary- for example, once you have built a ground truth dataset on a subset, many times you can start by building an index with the default build parameters and then playing around with different search parameters until you get the desired quality and search performance. For massive indexes that might be multiple terabytes, you could also take this subsampling of, say, 10M vectors, train an index and then tune the search parameters from there. While there might be a small margin of error, the chosen build/search parameters should generalize fairly well for the databases that build locally partitioned indexes. - -Refer to our :doc:`tuning guide ` for more information and examples on how to efficiently and automatically tune your vector search indexes based on your needs. diff --git a/docs/source/working_with_ann_indexes.rst b/docs/source/working_with_ann_indexes.rst deleted file mode 100644 index 8e91fb4acd..0000000000 --- a/docs/source/working_with_ann_indexes.rst +++ /dev/null @@ -1,11 +0,0 @@ -Working with ANN Indexes -======================== - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - working_with_ann_indexes_c.rst - working_with_ann_indexes_cpp.rst - working_with_ann_indexes_python.rst - working_with_ann_indexes_rust.rst diff --git a/docs/source/working_with_ann_indexes_c.rst b/docs/source/working_with_ann_indexes_c.rst deleted file mode 100644 index 1e84141a86..0000000000 --- a/docs/source/working_with_ann_indexes_c.rst +++ /dev/null @@ -1,62 +0,0 @@ -Working with ANN Indexes in C -============================= - -- `Building an index`_ -- `Searching an index`_ - -Building an index ------------------ - -.. code-block:: c - - #include - - cuvsResources_t res; - cuvsCagraIndexParams_t index_params; - cuvsCagraIndex_t index; - - DLManagedTensor *dataset; - - // populate tensor with data - load_dataset(dataset); - - cuvsResourcesCreate(&res); - cuvsCagraIndexParamsCreate(&index_params); - cuvsCagraIndexCreate(&index); - - cuvsCagraBuild(res, index_params, dataset, index); - - cuvsCagraIndexDestroy(index); - cuvsCagraIndexParamsDestroy(index_params); - cuvsResourcesDestroy(res); - - -Searching an index ------------------- - -.. code-block:: c - - #include - - cuvsResources_t res; - cuvsCagraSearchParams_t search_params; - cuvsCagraIndex_t index; - - // ... build index ... - - DLManagedTensor *queries; - - DLManagedTensor *neighbors; - DLManagedTensor *distances; - - // populate tensor with data - load_queries(queries); - - cuvsResourcesCreate(&res); - cuvsCagraSearchParamsCreate(&index_params); - - cuvsCagraSearch(res, search_params, index, queries, neighbors, distances); - - cuvsCagraIndexDestroy(index); - cuvsCagraIndexParamsDestroy(index_params); - cuvsResourcesDestroy(res); diff --git a/docs/source/working_with_ann_indexes_cpp.rst b/docs/source/working_with_ann_indexes_cpp.rst deleted file mode 100644 index 68578bf848..0000000000 --- a/docs/source/working_with_ann_indexes_cpp.rst +++ /dev/null @@ -1,43 +0,0 @@ -Working with ANN Indexes in C++ -=============================== - -- `Building an index`_ -- `Searching an index`_ - -Building an index ------------------ - -.. code-block:: c++ - - #include - - using namespace cuvs::neighbors; - - raft::device_matrix_view dataset = load_dataset(); - raft::device_resources res; - - cagra::index_params index_params; - - auto index = cagra::build(res, index_params, dataset); - - -Searching an index ------------------- - -.. code-block:: c++ - - #include - - using namespace cuvs::neighbors; - cagra::index index; - - // ... build index ... - - raft::device_matrix_view queries = load_queries(); - raft::device_matrix_view neighbors = make_device_matrix_view(n_queries, k); - raft::device_matrix_view distances = make_device_matrix_view(n_queries, k); - raft::device_resources res; - - cagra::search_params search_params; - - cagra::search(res, search_params, index, queries, neighbors, distances); diff --git a/docs/source/working_with_ann_indexes_python.rst b/docs/source/working_with_ann_indexes_python.rst deleted file mode 100644 index 0419c47beb..0000000000 --- a/docs/source/working_with_ann_indexes_python.rst +++ /dev/null @@ -1,33 +0,0 @@ -Working with ANN Indexes in Python -================================== - -- `Building an index`_ -- `Searching an index`_ - -Building an index ------------------ - -.. code-block:: python - - from cuvs.neighbors import cagra - - dataset = load_data() - index_params = cagra.IndexParams() - - index = cagra.build(build_params, dataset) - - -Searching an index ------------------- - -.. code-block:: python - - from cuvs.neighbors import cagra - - queries = load_queries() - - search_params = cagra.SearchParams() - - index = // ... build index ... - - neighbors, distances = cagra.search(search_params, index, queries, k) diff --git a/docs/source/working_with_ann_indexes_rust.rst b/docs/source/working_with_ann_indexes_rust.rst deleted file mode 100644 index 487ad0964b..0000000000 --- a/docs/source/working_with_ann_indexes_rust.rst +++ /dev/null @@ -1,62 +0,0 @@ -Working with ANN Indexes in Rust -================================ - -- `Building and Searching an index`_ - -Building and Searching an index -------------------------------- - -.. code-block:: rust - - use cuvs::cagra::{Index, IndexParams}; - use cuvs::{Resources, Result}; - - use ndarray_rand::rand_distr::Uniform; - use ndarray_rand::RandomExt; - - /// Example showing how to index and search data with CAGRA - fn cagra_example() -> Result<()> { - let res = Resources::new()?; - - // Create a new random dataset to index - let n_datapoints = 65536; - let n_features = 512; - let dataset = - ndarray::Array::::random((n_datapoints, n_features), Uniform::new(0., 1.0)); - - // build the cagra index - let build_params = IndexParams::new()?; - let index = Index::build(&res, &build_params, &dataset)?; - - // use the first 4 points from the dataset as queries : will test that we get them back - // as their own nearest neighbor - let n_queries = 4; - let queries = dataset.slice(s![0..n_queries, ..]); - - let k = 10; - - // CAGRA search API requires queries and outputs to be on device memory - // copy query data over, and allocate new device memory for the distances/ neighbors - // outputs - let queries = ManagedTensor::from(&queries).to_device(&res)?; - let mut neighbors_host = ndarray::Array::::zeros((n_queries, k)); - let neighbors = ManagedTensor::from(&neighbors_host).to_device(&res)?; - - let mut distances_host = ndarray::Array::::zeros((n_queries, k)); - let distances = ManagedTensor::from(&distances_host).to_device(&res)?; - - let search_params = SearchParams::new()?; - - index.search(&res, &search_params, &queries, &neighbors, &distances)?; - - // Copy back to host memory - distances.to_host(&res, &mut distances_host)?; - neighbors.to_host(&res, &mut neighbors_host)?; - - // nearest neighbors should be themselves, since queries are from the - // dataset - println!("Neighbors {:?}", neighbors_host); - println!("Distances {:?}", distances_host); - - Ok(()) - } diff --git a/fern/README.md b/fern/README.md new file mode 100644 index 0000000000..9c922c50c3 --- /dev/null +++ b/fern/README.md @@ -0,0 +1,39 @@ +# cuVS Fern documentation + +The cuVS documentation lives in this Fern project. Pages are in `fern/pages`, and the sidebar navigation is configured in `fern/docs.yml`. + +The C, C++, Python, Java, Rust, and Go API reference pages are generated from the source tree by `fern/scripts/generate_api_reference.py`. `fern/build_docs.sh` refreshes those pages before validation, preview, and publish runs. + +Fern requires Node.js 22 or newer. If the docs fail with an error such as `SyntaxError: Unexpected token '.'`, check `node --version` and activate a newer Node.js runtime. + +## Preview locally + +Start the local preview server from the repository root: + +```bash +fern/build_docs.sh dev +``` + +Fern serves the local preview at `http://localhost:3000` by default. + +## Validate + +Run Fern's checks before publishing changes: + +```bash +fern/build_docs.sh check +``` + +## Publish + +Create a Fern preview deployment: + +```bash +fern/build_docs.sh preview +``` + +Publish to the instance configured in `fern/docs.yml` with: + +```bash +fern/build_docs.sh publish +``` diff --git a/docs/source/images/build_benchmarks.png b/fern/assets/images/build_benchmarks.png similarity index 100% rename from docs/source/images/build_benchmarks.png rename to fern/assets/images/build_benchmarks.png diff --git a/fern/assets/images/clustering_methods_overview.png b/fern/assets/images/clustering_methods_overview.png new file mode 100644 index 0000000000..fb2e2a1c04 Binary files /dev/null and b/fern/assets/images/clustering_methods_overview.png differ diff --git a/fern/assets/images/diskann_disk_architecture.png b/fern/assets/images/diskann_disk_architecture.png new file mode 100644 index 0000000000..0940c677e7 Binary files /dev/null and b/fern/assets/images/diskann_disk_architecture.png differ diff --git a/fern/assets/images/globally_partitioned_index.svg b/fern/assets/images/globally_partitioned_index.svg new file mode 100644 index 0000000000..99817a06a0 --- /dev/null +++ b/fern/assets/images/globally_partitioned_index.svg @@ -0,0 +1,61 @@ + + Globally partitioned index architecture + A query first uses a global routing index to select relevant partitions, searches only those partitions, and merges the partial top-k results. + + + + + + + + Globally partitioned index + A global routing layer chooses the most relevant partitions before search. + + + Query + vector + + + Global + routing + centroids / IVF + + + Partition 1 + searched ANN index + + + Partition 2 + searched ANN index + + + Partition 3 + usually skipped + + + Merge + partial top-k + + + Final + results + + + + + + + + + + diff --git a/fern/assets/images/graph_index_build_search.png b/fern/assets/images/graph_index_build_search.png new file mode 100644 index 0000000000..17df31ed19 Binary files /dev/null and b/fern/assets/images/graph_index_build_search.png differ diff --git a/fern/assets/images/hash_ivf_graph_index.png b/fern/assets/images/hash_ivf_graph_index.png new file mode 100644 index 0000000000..43770f148c Binary files /dev/null and b/fern/assets/images/hash_ivf_graph_index.png differ diff --git a/fern/assets/images/hash_partition_build_search.png b/fern/assets/images/hash_partition_build_search.png new file mode 100644 index 0000000000..eea8609270 Binary files /dev/null and b/fern/assets/images/hash_partition_build_search.png differ diff --git a/docs/source/images/index_recalls.png b/fern/assets/images/index_recalls.png similarity index 100% rename from docs/source/images/index_recalls.png rename to fern/assets/images/index_recalls.png diff --git a/fern/assets/images/ivf_flat_index.png b/fern/assets/images/ivf_flat_index.png new file mode 100644 index 0000000000..bbd656b4e9 Binary files /dev/null and b/fern/assets/images/ivf_flat_index.png differ diff --git a/fern/assets/images/ivf_index_build_search.png b/fern/assets/images/ivf_index_build_search.png new file mode 100644 index 0000000000..d18ab102a2 Binary files /dev/null and b/fern/assets/images/ivf_index_build_search.png differ diff --git a/fern/assets/images/ivf_vs_graph_index.png b/fern/assets/images/ivf_vs_graph_index.png new file mode 100644 index 0000000000..e25ceb010e Binary files /dev/null and b/fern/assets/images/ivf_vs_graph_index.png differ diff --git a/fern/assets/images/locally_partitioned_index.svg b/fern/assets/images/locally_partitioned_index.svg new file mode 100644 index 0000000000..d99fe4c62e --- /dev/null +++ b/fern/assets/images/locally_partitioned_index.svg @@ -0,0 +1,53 @@ + + Locally partitioned index architecture + A query fans out to every local partition, each partition searches its own ANN index, and the database merges the partial top-k results. + + + + + + + + Locally partitioned index + Each query visits every local partition, then merges the partial results. + + + Query + vector + + + Partition 1 + local ANN index + + + Partition 2 + local ANN index + + + Partition 3 + local ANN index + + + Merge + partial top-k + + + Final + results + + + + + + + + + + diff --git a/fern/assets/images/pareto_curve_vector_search.svg b/fern/assets/images/pareto_curve_vector_search.svg new file mode 100644 index 0000000000..3053e4056f --- /dev/null +++ b/fern/assets/images/pareto_curve_vector_search.svg @@ -0,0 +1,67 @@ + + Example Pareto curve for vector search tuning + A scatter plot of vector search tuning runs. Green points on the lower-right frontier are Pareto choices because no other run has both higher search quality and lower latency. Gray points are dominated by better choices. + + + + + + + + + Pareto curve example + Each point is one vector search tuning run. Better runs move right and down. + + + + + + + + + + + + + Search quality / recall + higher is better + Search latency + lower is better + + + + + + + + + + + + + + + + + + + + + Pareto point + + Dominated run + + Pareto curve + + diff --git a/docs/source/images/recall_buckets.png b/fern/assets/images/recall_buckets.png similarity index 100% rename from docs/source/images/recall_buckets.png rename to fern/assets/images/recall_buckets.png diff --git a/fern/assets/images/refinement_reranking.png b/fern/assets/images/refinement_reranking.png new file mode 100644 index 0000000000..e52d13efd4 Binary files /dev/null and b/fern/assets/images/refinement_reranking.png differ diff --git a/fern/assets/images/tech_stack.png b/fern/assets/images/tech_stack.png new file mode 100644 index 0000000000..65ffe57f49 Binary files /dev/null and b/fern/assets/images/tech_stack.png differ diff --git a/fern/assets/rapids_logo.png b/fern/assets/rapids_logo.png new file mode 100644 index 0000000000..405040836a Binary files /dev/null and b/fern/assets/rapids_logo.png differ diff --git a/fern/build_docs.sh b/fern/build_docs.sh new file mode 100755 index 0000000000..3dd001814b --- /dev/null +++ b/fern/build_docs.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REPO_DIR=$(cd "${SCRIPT_DIR}/.." && pwd) +MODE="${1:-check}" + +if [[ $# -gt 0 ]]; then + shift +fi + +usage() { + cat <<'EOF' +Usage: fern/build_docs.sh [check|preview|publish|dev] [fern arguments...] + +Modes: + check Validate Fern configuration, links, and Markdown syntax. + preview Build and publish a Fern preview deployment. + publish Build and publish the production Fern docs site. + dev Start Fern's local docs preview server. + +Examples: + fern/build_docs.sh + fern/build_docs.sh preview --id pr-123 --force + fern/build_docs.sh publish --instance rapids-cuvs.docs.buildwithfern.com + fern/build_docs.sh dev --port 3002 +EOF +} + +require_node_22() { + if ! command -v node >/dev/null 2>&1; then + echo "Fern docs require Node.js 22 or newer, but node was not found on PATH." >&2 + echo "Install or activate Node.js 22+ before running fern/build_docs.sh." >&2 + exit 1 + fi + + local node_version + local node_major + node_version=$(node -p 'process.versions.node' 2>/dev/null || true) + node_major="${node_version%%.*}" + + if [[ ! "${node_major}" =~ ^[0-9]+$ || "${node_major}" -lt 22 ]]; then + echo "Fern docs require Node.js 22 or newer, but found Node.js ${node_version:-unknown}." >&2 + echo "Older Node.js versions can fail with errors such as \"SyntaxError: Unexpected token '.'.\"" >&2 + echo "Install or activate Node.js 22+ before running fern/build_docs.sh." >&2 + exit 1 + fi +} + +require_node_22 + +if [[ -n "${FERN_CLI:-}" ]]; then + FERN_CMD=("${FERN_CLI}") +elif command -v fern >/dev/null 2>&1; then + FERN_CMD=("fern") +else + FERN_CMD=("npx" "--yes" "fern-api") +fi + +run_fern() { + "${FERN_CMD[@]}" "$@" +} + +generate_api_reference() { + python3 "${SCRIPT_DIR}/scripts/generate_api_reference.py" +} + +run_checks() { + pushd "${REPO_DIR}" >/dev/null + run_fern check --warnings + run_fern docs md check + popd >/dev/null +} + +case "${MODE}" in + check) + generate_api_reference + run_checks + ;; + preview) + generate_api_reference + run_checks + pushd "${REPO_DIR}" >/dev/null + run_fern generate --docs --preview "$@" + popd >/dev/null + ;; + publish) + generate_api_reference + run_checks + pushd "${REPO_DIR}" >/dev/null + run_fern generate --docs "$@" + popd >/dev/null + ;; + dev) + generate_api_reference + pushd "${REPO_DIR}" >/dev/null + run_fern docs dev "$@" + popd >/dev/null + ;; + -h|--help|help) + usage + ;; + *) + echo "Unknown mode: ${MODE}" >&2 + echo >&2 + usage >&2 + exit 2 + ;; +esac diff --git a/fern/developer_guide/abi_stability.md b/fern/developer_guide/abi_stability.md new file mode 100644 index 0000000000..702bc07f42 --- /dev/null +++ b/fern/developer_guide/abi_stability.md @@ -0,0 +1,367 @@ +# ABI Stability Guarantees + +## Overview + +ABI stands for **Application Binary Interface**. It defines how compiled programs interact with a shared library at runtime. + +For cuVS, ABI stability means that an application built against one supported version of the **cuVS C library** can run with a compatible newer cuVS runtime without needing to be rebuilt. + +For example: + +```text +Application built against: cuVS 26.04 +Runtime installed by user: cuVS 26.06 + +Result: works, as long as both versions use the same ABI major version +``` + +ABI stability is different from API stability: + +| Concept | Meaning | +|---|---| +| API stability | Source code continues to compile. | +| ABI stability | Already-compiled binaries continue to run. | + +A source-compatible change may still break ABI if it changes the binary layout, symbol names, function signatures, or expected runtime behavior. + +--- + +## Why ABI Stability Is Needed + +cuVS is used by downstream projects and language bindings such as Java, Rust, Go, and database integrations. + +These users often want to build their application once and allow the final runtime environment to provide cuVS separately. Without ABI stability, downstream consumers may need to rebuild or repackage every time cuVS changes. + +ABI stability enables this model: + +```text +Vendor application + built once against a supported cuVS version + +User environment + provides a compatible cuVS shared library + +Result + the application can load and run without being rebuilt +``` + +This is especially important for database vendors and other software providers that do not want to vendor or bundle a private copy of cuVS with every release. + +ABI stability helps provide: + +- Predictable runtime compatibility +- Smaller downstream packages +- Easier system-level deployment +- Safer upgrades for users +- Clear rules for when breaking changes are allowed + +--- + +## ABI Compatibility Rule + +A cuVS runtime is ABI-compatible with an application when both of the following are true: + +1. The runtime has the **same ABI major version** as the version used at build time. +2. The runtime cuVS version is the **same or newer** than the version used at build time. + +Example compatibility matrix: + +| Built With | Runtime | Compatible? | Reason | +|---|---:|---:|---| +| cuVS 26.04, ABI 1.1 | cuVS 26.06, ABI 1.2 | Yes | Same ABI major, newer runtime | +| cuVS 26.04, ABI 1.1 | cuVS 26.02, ABI 1.0 | No | Runtime is older | +| cuVS 26.04, ABI 1.1 | cuVS 26.08, ABI 2.0 | No | ABI major changed | + +--- + +## Shared Library Naming + +The cuVS C shared library follows this pattern: + +```text +libcuvs_c.so.. +``` + +For example: + +```text +libcuvs_c.so.1.2 +``` + +Where: + +```text +1 = ABI major version +2 = ABI minor version +``` + +The SONAME uses only the ABI major version: + +```text +libcuvs_c.so.1 +``` + +Applications that dynamically load cuVS should load the ABI-major versioned name: + +```text +libcuvs_c.so.1 +``` + +They should not load the fully specified file name: + +```text +libcuvs_c.so.1.2 +``` + +Loading the ABI-major versioned name allows compatible ABI-minor updates to work without relinking or rebuilding the application. + +--- + +## Scope of the ABI Guarantee + +The ABI stability guarantee applies to the public **C ABI**. + +It applies to public C interface items that meet these conditions: + +- They are installed under `include/cuvs/` +- They are declared in `.h` header files +- They are inside an `extern "C"` block +- They are part of the public cuVS C interface + +The guarantee covers public C functions, enums, and structs that are exposed through the stable C interface. + +It does not generally apply to internal implementation details or to the general C++ implementation ABI. + +--- + +## Struct Stability + +Structs require special care. + +A struct is only ABI-stable when it is allocated, initialized, or managed by ABI-stable cuVS functions. User code should not directly depend on the internal layout of cuVS structs. + +Recommended pattern: + +```c +cuvsHnswIndex_t index; +cuvsHnswIndexCreate(&index); + +cuvsHnswIndexParams_t params; +cuvsHnswIndexParamsCreate(¶ms); + +cuvsHnswFromCagra(res, params, cagra_index, index); +``` + +Avoid this pattern: + +```c +cuvsHnswIndex index = { ... }; +cuvsHnswIndexParams params = { ... }; + +cuvsHnswFromCagra(res, ¶ms, cagra_index, &index); +``` + +The second example is risky because it depends on struct layout. If cuVS later adds, removes, reorders, or changes fields, compiled applications may break. + +--- + +# Developer Guide: How to Avoid Breaking ABI + +## General Rule + +When changing public C headers, assume that existing applications may already be compiled against the current ABI. + +Use this rule of thumb: + +```text +Adding a new symbol is usually safe. +Changing an existing symbol is usually unsafe. +Removing an existing symbol is an ABI break. +``` + +--- + +## Safe Changes in ABI-Compatible Releases + +The following changes are generally safe during ABI-compatible releases: + +- Add a new public C function +- Add a new enum value when it does not change existing values or behavior +- Add new functionality behind a new symbol +- Add fields to structs that are fully allocated and managed by cuVS +- Add new optional behavior without changing existing function signatures +- Add new APIs while leaving old APIs intact + +Example of a safe additive change: + +```c +cuvsStatus_t cuvsFoo(cuvsHandle_t handle, int n); + +/* New symbol added later */ +cuvsStatus_t cuvsFooWithOptions( + cuvsHandle_t handle, + int n, + cuvsFooOptions_t options +); +``` + +The original function remains unchanged, so existing binaries continue to work. + +--- + +## Unsafe Changes in ABI-Compatible Releases + +Do not make these changes in ABI-compatible releases: + +- Remove a public function +- Rename a public function +- Change a function return type +- Add, remove, or reorder function arguments +- Change the type of a function argument +- Change the size or layout of a public struct that users may construct directly +- Remove or rename struct fields +- Change the type of a struct field +- Remove or renumber enum values +- Change the meaning of an existing enum value +- Change behavior in a way that violates existing runtime expectations + +Example of an ABI break: + +```c +/* Original */ +cuvsStatus_t cuvsFoo(cuvsHandle_t handle, int n); + +/* ABI-breaking change */ +cuvsStatus_t cuvsFoo(cuvsHandle_t handle, int64_t n); +``` + +Even though the function name is the same, the binary signature changed. + +--- + +## How to Make an Incompatible Change Safely + +If a function needs an incompatible signature, do not change the existing function directly. + +Instead, add a new suffixed function. + +Example: + +```c +/* Existing ABI-stable function */ +cuvsStatus_t cuvsFoo(cuvsHandle_t handle, int n); + +/* New replacement function */ +cuvsStatus_t cuvsFoo_v1( + cuvsHandle_t handle, + int64_t n, + float threshold +); +``` + +The old function remains available for existing binaries. New applications can use the new suffixed function. + +The old function should be documented as deprecated or superseded, and release notes should explain which replacement should be used. + +--- + +## Consolidating During ABI-Breaking Releases + +cuVS has planned releases where ABI-breaking changes are allowed. These are the releases where accumulated compatibility work can be consolidated. + +During normal ABI-compatible releases, developers may accumulate suffixed replacement APIs: + +```c +cuvsStatus_t cuvsFoo(...); +cuvsStatus_t cuvsFoo_v1(...); +cuvsStatus_t cuvsFoo_v5(...); +``` + +During an ABI-breaking release, the highest replacement can become the canonical unsuffixed API: + +```c +cuvsStatus_t cuvsFoo(...); +``` + +For example: + +```text +ABI 1.x: + cuvsFoo() + cuvsFoo_v1() + cuvsFoo_v5() + +ABI 2.0: + cuvsFoo() now uses the cuvsFoo_v5 signature +``` + +At that point, older variants can be removed because the ABI major version has changed. + +--- + +## ABI-Breaking Release Checklist + +When performing ABI consolidation during a planned ABI-breaking release: + +- Bump the ABI major version +- Update the SONAME +- Remove obsolete symbols that are no longer supported +- Promote the latest suffixed replacement to the canonical unsuffixed API +- Update public headers +- Update documentation +- Update release notes +- Update the compatibility matrix +- Update ABI baseline or ABI checking data +- Ensure packaging uses the correct shared library version +- Clearly document old signatures and their replacements + +Example transition: + +```text +Before: + libcuvs_c.so.1 + cuvsFoo() + cuvsFoo_v1() + cuvsFoo_v5() + +After: + libcuvs_c.so.2 + cuvsFoo() // uses the cuvsFoo_v5 behavior/signature +``` + +--- + +# Practical Checklist for Developers + +Before modifying a public C header, ask: + +- Is this header installed under `include/cuvs/`? +- Is this declaration inside `extern "C"`? +- Could downstream code already be compiled against this symbol? +- Am I changing a function name, return type, or parameter list? +- Am I changing an enum value or its meaning? +- Am I changing a struct layout that user code may depend on? +- Would an already-compiled application still load and call this correctly? +- Should this be a new suffixed symbol instead of a direct change? + +Use this decision guide: + +| Change | Allowed in ABI-compatible release? | Recommended approach | +|---|---:|---| +| Add a new function | Yes | Add a new symbol | +| Change a function signature | No | Add a suffixed replacement | +| Remove a function | No | Wait for ABI-breaking release | +| Rename a function | No | Add new function, keep old one | +| Add managed struct fields | Usually | Only if users cannot construct the struct directly | +| Change public struct layout | Risky | Avoid, or wait for ABI-breaking release | +| Remove enum value | No | Wait for ABI-breaking release | + +--- + +# Summary + +ABI stability lets applications built against one cuVS C library version run with compatible newer cuVS runtimes without being rebuilt. + +Developers should preserve existing public C ABI symbols during ABI-compatible releases. Add new symbols instead of changing existing ones. When an incompatible change is required, introduce a suffixed replacement such as `_v1`, keep the old symbol available, and document the migration path. + +During planned ABI-breaking releases, developers can consolidate these suffixed replacements by promoting the newest version to the canonical unsuffixed API, removing obsolete variants, and incrementing the ABI major version. diff --git a/fern/docs.yml b/fern/docs.yml new file mode 100644 index 0000000000..810bd8f1eb --- /dev/null +++ b/fern/docs.yml @@ -0,0 +1,523 @@ +# yaml-language-server: $schema=https://schema.buildwithfern.dev/docs-yml.json + +title: "cuVS" +instances: + - url: "nvidia-cuvs.docs.buildwithfern.com/cuvs" + custom-domain: docs.nvidia.com/cuvs +footer: "./theme/nvidia/components/CustomFooter.tsx" +logo: + light: "./theme/nvidia/assets/NVIDIA_light.svg" + dark: "./theme/nvidia/assets/NVIDIA_dark.svg" + height: 20 + href: "https://developer.nvidia.com/cuvs" + right-text: "cuVS" +favicon: "./theme/nvidia/assets/NVIDIA_symbol.svg" +colors: + accentPrimary: + light: "#76B900" + dark: "#76B900" + background: + light: "#FFFFFF" + dark: "#000000" + accent-primary: + light: "#76B900" + dark: "#A4E600" +check: + rules: + broken-links: "error" +redirects: + - source: "/cuvs/developer-guide/guidelines/c-guidelines" + destination: "/cuvs/developer-guide/coding-guidelines/cpp-guidelines" + - source: "/cuvs/developer-guide/guidelines/python-guidelines" + destination: "/cuvs/developer-guide/coding-guidelines/python-guidelines" +layout: + searchbar-placement: "header" + page-width: "1376px" + sidebar-width: "248px" + content-width: "812px" + tabs-placement: "header" + hide-feedback: true +theme: + page-actions: "toolbar" + footer-nav: "minimal" +css: + - "./theme/nvidia/main.css" + - "./styles/authors.css" + - "./styles/expandable-code.css" + - "./styles/metrics-table.css" + - "./styles/notebook-viewer.css" + - "./styles/trajectory-viewer.css" +experimental: + mdx-components: + - "./theme/nvidia/components" + basepath-aware: true +navbar-links: + - type: "secondary" + text: "GitHub" + url: "https://github.com/rapidsai/cuvs" + - type: "secondary" + text: "CUDA-X" + url: "https://www.nvidia.com/en-us/technologies/cuda-x/" +navigation: + - page: "Home" + path: "./pages/index.md" + - section: "Installation" + path: "./pages/build.md" + collapsed: true + contents: + - page: "C" + path: "./pages/installation/c.md" + - page: "C++" + slug: "cpp" + path: "./pages/installation/cpp.md" + - page: "Python" + path: "./pages/installation/python.md" + - page: "Java" + path: "./pages/installation/java.md" + - page: "Go" + path: "./pages/installation/go.md" + - page: "Rust" + path: "./pages/installation/rust.md" + - section: "Getting Started" + path: "./pages/getting_started.md" + contents: + - section: "Introduction" + path: "./pages/introduction.md" + contents: + - page: "Vector Search" + path: "./pages/what_is_vector_search.md" + - page: "Clustering" + path: "./pages/clustering.md" + - page: "Compression" + path: "./pages/quantization.md" + - page: "Vector Database" + path: "./pages/vector_databases_vs_vector_search.md" + - page: "Tuning Indexes" + path: "./pages/tuning_guide.md" + - page: "Integrations" + path: "./pages/integrations.md" + - page: "Use-cases" + path: "./pages/use_cases.md" + - page: "Using cuVS APIs" + hidden: true + path: "./pages/working_with_ann_indexes.md" + - section: "User Guide" + path: "./pages/user_guide.md" + contents: + - page: "cuVS API Basics" + hidden: true + path: "./pages/api_basics.md" + - page: "Interoperability" + hidden: true + path: "./pages/api_interoperability.md" + - section: "API Guide" + path: "./pages/api_guide.md" + collapsed: true + contents: + - section: "Clustering Guide" + path: "./pages/cluster/index.md" + contents: + - page: "K-Means" + path: "./pages/cluster/kmeans.md" + - page: "Single-linkage" + path: "./pages/cluster/single_linkage.md" + - page: "Spectral Clustering" + path: "./pages/cluster/spectral.md" + - section: "Indexing Guide" + path: "./pages/neighbors/neighbors.md" + contents: + - page: "All-neighbors" + path: "./pages/neighbors/all_neighbors.md" + - page: "Brute-force" + path: "./pages/neighbors/bruteforce.md" + - page: "CAGRA" + path: "./pages/neighbors/cagra.md" + - page: "IVF-Flat" + path: "./pages/neighbors/ivfflat.md" + - page: "IVF-PQ" + path: "./pages/neighbors/ivfpq.md" + - page: "Multi-GPU" + path: "./pages/neighbors/multi_gpu.md" + - page: "NN-Descent" + path: "./pages/neighbors/nn_descent.md" + - page: "ScaNN" + path: "./pages/neighbors/scann.md" + - page: "Vamana" + path: "./pages/neighbors/vamana.md" + - section: "Preprocessing Guide" + path: "./pages/preprocessing/index.md" + contents: + - page: "Binary Quantizer" + path: "./pages/preprocessing/binary_quantizer.md" + - page: "PCA" + path: "./pages/preprocessing/pca.md" + - page: "Product Quantization" + path: "./pages/preprocessing/product_quantization.md" + - page: "Scalar Quantizer" + path: "./pages/preprocessing/scalar_quantizer.md" + - page: "Spectral Embedding" + path: "./pages/preprocessing/spectral_embedding.md" + - section: "Other APIs" + path: "./pages/other/index.md" + contents: + - page: "Dynamic Batching" + path: "./pages/other/dynamic_batching.md" + - page: "K-selection" + path: "./pages/other/select_k.md" + - page: "Pairwise Distances" + path: "./pages/other/pairwise_distances.md" + - section: "Benchmarking Guide" + path: "./pages/benchmarking_guide.md" + contents: + - page: "Methodologies" + path: "./pages/comparing_indexes.md" + - section: "cuVS Bench Tool" + path: "./pages/cuvs_bench/index.md" + contents: + - page: "Introduction" + path: "./pages/cuvs_bench/introduction.md" + - page: "Installation" + path: "./pages/cuvs_bench/install.md" + - page: "Usage" + path: "./pages/cuvs_bench/running.md" + - page: "Datasets" + path: "./pages/cuvs_bench/datasets.md" + - page: "Backends" + path: "./pages/cuvs_bench/pluggable_backend.md" + - page: "cuVS Bench Parameter Tuning Guide" + hidden: true + path: "./pages/cuvs_bench/param_tuning.md" + - page: "Wiki-all Dataset" + hidden: true + path: "./pages/cuvs_bench/wiki_all_dataset.md" + - page: "Compatibility" + path: "./pages/user_guide/abi_stability.md" + - page: "Integration Patterns" + path: "./pages/user_guide/integration_patterns.md" + - page: "References" + path: "./pages/references.md" + - section: "Developer Guide" + path: "./pages/developer_guide.md" + contents: + - section: "Coding Guidelines" + path: "./pages/coding_guidelines.md" + contents: + - page: "C Guidelines" + path: "./pages/c_guidelines.md" + - page: "C++ Guidelines" + path: "./pages/cpp_guidelines.md" + - page: "Java Guidelines" + path: "./pages/java_guidelines.md" + - page: "Python Guidelines" + path: "./pages/python_guidelines.md" + - section: "Advanced Topics" + path: "./pages/advanced_topics.md" + contents: + - page: "ABI Stability" + path: "./developer_guide/abi_stability.md" + - page: "JIT Compilation" + path: "./pages/jit_compilation.md" + - page: "Link-time Optimization" + path: "./pages/jit_lto_guide.md" + - page: "Contributing" + path: "./pages/contributing.md" + - section: "API Reference" + contents: + - section: "C API Documentation" + path: "./pages/c_api/index.md" + contents: + - page: "Cluster Kmeans" + path: "./pages/c_api/c-api-cluster-kmeans.md" + - page: "Core C API" + path: "./pages/c_api/c-api-core-c-api.md" + - page: "Distance Distance" + path: "./pages/c_api/c-api-distance-distance.md" + - page: "Distance Pairwise Distance" + path: "./pages/c_api/c-api-distance-pairwise-distance.md" + - page: "Neighbors All Neighbors" + path: "./pages/c_api/c-api-neighbors-all-neighbors.md" + - page: "Neighbors Brute Force" + path: "./pages/c_api/c-api-neighbors-brute-force.md" + - page: "Neighbors Cagra" + path: "./pages/c_api/c-api-neighbors-cagra.md" + - page: "Neighbors Common" + path: "./pages/c_api/c-api-neighbors-common.md" + - page: "Neighbors HNSW" + path: "./pages/c_api/c-api-neighbors-hnsw.md" + - page: "Neighbors IVF Flat" + path: "./pages/c_api/c-api-neighbors-ivf-flat.md" + - page: "Neighbors IVF PQ" + path: "./pages/c_api/c-api-neighbors-ivf-pq.md" + - page: "Neighbors Multi GPU Cagra" + path: "./pages/c_api/c-api-neighbors-mg-cagra.md" + - page: "Neighbors Multi GPU Common" + path: "./pages/c_api/c-api-neighbors-mg-common.md" + - page: "Neighbors Multi GPU IVF Flat" + path: "./pages/c_api/c-api-neighbors-mg-ivf-flat.md" + - page: "Neighbors Multi GPU IVF PQ" + path: "./pages/c_api/c-api-neighbors-mg-ivf-pq.md" + - page: "Neighbors NN Descent" + path: "./pages/c_api/c-api-neighbors-nn-descent.md" + - page: "Neighbors Refine" + path: "./pages/c_api/c-api-neighbors-refine.md" + - page: "Neighbors Tiered Index" + path: "./pages/c_api/c-api-neighbors-tiered-index.md" + - page: "Neighbors Vamana" + path: "./pages/c_api/c-api-neighbors-vamana.md" + - page: "Preprocessing PCA" + path: "./pages/c_api/c-api-preprocessing-pca.md" + - page: "Preprocessing Quantize Binary" + path: "./pages/c_api/c-api-preprocessing-quantize-binary.md" + - page: "Preprocessing Quantize PQ" + path: "./pages/c_api/c-api-preprocessing-quantize-pq.md" + - page: "Preprocessing Quantize Scalar" + path: "./pages/c_api/c-api-preprocessing-quantize-scalar.md" + - section: "Cpp API Documentation" + path: "./pages/cpp_api/index.md" + contents: + - page: "Cluster Agglomerative" + path: "./pages/cpp_api/cpp-api-cluster-agglomerative.md" + - page: "Cluster Kmeans" + path: "./pages/cpp_api/cpp-api-cluster-kmeans.md" + - page: "Cluster Spectral" + path: "./pages/cpp_api/cpp-api-cluster-spectral.md" + - page: "Distance Distance" + path: "./pages/cpp_api/cpp-api-distance-distance.md" + - page: "Distance Grammian" + path: "./pages/cpp_api/cpp-api-distance-grammian.md" + - page: "Neighbors All Neighbors" + path: "./pages/cpp_api/cpp-api-neighbors-all-neighbors.md" + - page: "Neighbors Ball Cover" + path: "./pages/cpp_api/cpp-api-neighbors-ball-cover.md" + - page: "Neighbors Brute Force" + path: "./pages/cpp_api/cpp-api-neighbors-brute-force.md" + - page: "Neighbors Cagra" + path: "./pages/cpp_api/cpp-api-neighbors-cagra.md" + - page: "Neighbors Common" + path: "./pages/cpp_api/cpp-api-neighbors-common.md" + - page: "Neighbors Composite Index" + path: "./pages/cpp_api/cpp-api-neighbors-composite-index.md" + - page: "Neighbors Dynamic Batching" + path: "./pages/cpp_api/cpp-api-neighbors-dynamic-batching.md" + - page: "Neighbors Epsilon Neighborhood" + path: "./pages/cpp_api/cpp-api-neighbors-epsilon-neighborhood.md" + - page: "Neighbors HNSW" + path: "./pages/cpp_api/cpp-api-neighbors-hnsw.md" + - page: "Neighbors IVF Flat" + path: "./pages/cpp_api/cpp-api-neighbors-ivf-flat.md" + - page: "Neighbors IVF PQ" + path: "./pages/cpp_api/cpp-api-neighbors-ivf-pq.md" + - page: "Neighbors NN Descent" + path: "./pages/cpp_api/cpp-api-neighbors-nn-descent.md" + - page: "Neighbors Refine" + path: "./pages/cpp_api/cpp-api-neighbors-refine.md" + - page: "Neighbors Scann" + path: "./pages/cpp_api/cpp-api-neighbors-scann.md" + - page: "Neighbors Tiered Index" + path: "./pages/cpp_api/cpp-api-neighbors-tiered-index.md" + - page: "Neighbors Vamana" + path: "./pages/cpp_api/cpp-api-neighbors-vamana.md" + - page: "Preprocessing PCA" + path: "./pages/cpp_api/cpp-api-preprocessing-pca.md" + - page: "Preprocessing Quantize Binary" + path: "./pages/cpp_api/cpp-api-preprocessing-quantize-binary.md" + - page: "Preprocessing Quantize PQ" + path: "./pages/cpp_api/cpp-api-preprocessing-quantize-pq.md" + - page: "Preprocessing Quantize Scalar" + path: "./pages/cpp_api/cpp-api-preprocessing-quantize-scalar.md" + - page: "Preprocessing Spectral Embedding" + path: "./pages/cpp_api/cpp-api-preprocessing-spectral-embedding.md" + - page: "Selection Select K" + path: "./pages/cpp_api/cpp-api-selection-select-k.md" + - page: "Stats Silhouette Score" + path: "./pages/cpp_api/cpp-api-stats-silhouette-score.md" + - page: "Stats Trustworthiness Score" + path: "./pages/cpp_api/cpp-api-stats-trustworthiness-score.md" + - page: "Util Cutlass Utils" + path: "./pages/cpp_api/cpp-api-util-cutlass-utils.md" + - page: "Util File Io" + path: "./pages/cpp_api/cpp-api-util-file-io.md" + - section: "Python API Documentation" + path: "./pages/python_api/index.md" + contents: + - page: "Cluster Kmeans" + path: "./pages/python_api/python-api-cluster-kmeans.md" + - page: "Common" + path: "./pages/python_api/python-api-common.md" + - page: "Distance" + path: "./pages/python_api/python-api-distance.md" + - page: "Neighbors Multi GPU Cagra" + path: "./pages/python_api/python-api-neighbors-mg-cagra.md" + - page: "Neighbors Multi GPU IVF Flat" + path: "./pages/python_api/python-api-neighbors-mg-ivf-flat.md" + - page: "Neighbors Multi GPU IVF PQ" + path: "./pages/python_api/python-api-neighbors-mg-ivf-pq.md" + - page: "Neighbors All Neighbors" + path: "./pages/python_api/python-api-neighbors-all-neighbors.md" + - page: "Neighbors Brute Force" + path: "./pages/python_api/python-api-neighbors-brute-force.md" + - page: "Neighbors Cagra" + path: "./pages/python_api/python-api-neighbors-cagra.md" + - page: "Neighbors Filters" + path: "./pages/python_api/python-api-neighbors-filters.md" + - page: "Neighbors HNSW" + path: "./pages/python_api/python-api-neighbors-hnsw.md" + - page: "Neighbors IVF Flat" + path: "./pages/python_api/python-api-neighbors-ivf-flat.md" + - page: "Neighbors IVF PQ" + path: "./pages/python_api/python-api-neighbors-ivf-pq.md" + - page: "Neighbors NN Descent" + path: "./pages/python_api/python-api-neighbors-nn-descent.md" + - page: "Neighbors" + path: "./pages/python_api/python-api-neighbors.md" + - page: "Neighbors Tiered Index" + path: "./pages/python_api/python-api-neighbors-tiered-index.md" + - page: "Neighbors Vamana" + path: "./pages/python_api/python-api-neighbors-vamana.md" + - page: "Preprocessing Quantize Binary" + path: "./pages/python_api/python-api-preprocessing-quantize-binary.md" + - page: "Preprocessing PCA" + path: "./pages/python_api/python-api-preprocessing-pca.md" + - page: "Preprocessing Quantize PQ" + path: "./pages/python_api/python-api-preprocessing-quantize-pq.md" + - page: "Preprocessing Quantize Scalar" + path: "./pages/python_api/python-api-preprocessing-quantize-scalar.md" + - section: "Java API Documentation" + path: "./pages/java_api/index.md" + contents: + - page: "Com Nvidia cuVS Bruteforceindex" + path: "./pages/java_api/java-api-com-nvidia-cuvs-bruteforceindex.md" + - page: "Com Nvidia cuVS Bruteforceindexparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-bruteforceindexparams.md" + - page: "Com Nvidia cuVS Bruteforcequery" + path: "./pages/java_api/java-api-com-nvidia-cuvs-bruteforcequery.md" + - page: "Com Nvidia cuVS Cagracompressionparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagracompressionparams.md" + - page: "Com Nvidia cuVS Cagraindex" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagraindex.md" + - page: "Com Nvidia cuVS Cagraindexparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagraindexparams.md" + - page: "Com Nvidia cuVS Cagramergeparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagramergeparams.md" + - page: "Com Nvidia cuVS Cagraquery" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagraquery.md" + - page: "Com Nvidia cuVS Cagrasearchparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cagrasearchparams.md" + - page: "Com Nvidia cuVS Cuvsaceparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsaceparams.md" + - page: "Com Nvidia cuVS Cuvsdevicematrix" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsdevicematrix.md" + - page: "Com Nvidia cuVS Cuvshostmatrix" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvshostmatrix.md" + - page: "Com Nvidia cuVS Cuvsivfpqindexparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsivfpqindexparams.md" + - page: "Com Nvidia cuVS Cuvsivfpqparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsivfpqparams.md" + - page: "Com Nvidia cuVS Cuvsivfpqsearchparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsivfpqsearchparams.md" + - page: "Com Nvidia cuVS Cuvsmatrix" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsmatrix.md" + - page: "Com Nvidia cuVS Cuvsresources" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsresources.md" + - page: "Com Nvidia cuVS Cuvsresourcesinfo" + path: "./pages/java_api/java-api-com-nvidia-cuvs-cuvsresourcesinfo.md" + - page: "Com Nvidia cuVS Delegatingscopedaccess" + path: "./pages/java_api/java-api-com-nvidia-cuvs-delegatingscopedaccess.md" + - page: "Com Nvidia cuVS Gpuinfo" + path: "./pages/java_api/java-api-com-nvidia-cuvs-gpuinfo.md" + - page: "Com Nvidia cuVS Gpuinfoprovider" + path: "./pages/java_api/java-api-com-nvidia-cuvs-gpuinfoprovider.md" + - page: "Com Nvidia cuVS Hnswaceparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-hnswaceparams.md" + - page: "Com Nvidia cuVS Hnswindex" + path: "./pages/java_api/java-api-com-nvidia-cuvs-hnswindex.md" + - page: "Com Nvidia cuVS Hnswindexparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-hnswindexparams.md" + - page: "Com Nvidia cuVS Hnswquery" + path: "./pages/java_api/java-api-com-nvidia-cuvs-hnswquery.md" + - page: "Com Nvidia cuVS Hnswsearchparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-hnswsearchparams.md" + - page: "Com Nvidia cuVS Libraryexception" + path: "./pages/java_api/java-api-com-nvidia-cuvs-libraryexception.md" + - page: "Com Nvidia cuVS Rowview" + path: "./pages/java_api/java-api-com-nvidia-cuvs-rowview.md" + - page: "Com Nvidia cuVS Searchresults" + path: "./pages/java_api/java-api-com-nvidia-cuvs-searchresults.md" + - page: "Com Nvidia cuVS Synchronizedcuvsresources" + path: "./pages/java_api/java-api-com-nvidia-cuvs-synchronizedcuvsresources.md" + - page: "Com Nvidia cuVS Tieredindex" + path: "./pages/java_api/java-api-com-nvidia-cuvs-tieredindex.md" + - page: "Com Nvidia cuVS Tieredindexparams" + path: "./pages/java_api/java-api-com-nvidia-cuvs-tieredindexparams.md" + - page: "Com Nvidia cuVS Tieredindexquery" + path: "./pages/java_api/java-api-com-nvidia-cuvs-tieredindexquery.md" + - page: "Com Nvidia cuVS Spi Cuvsprovider" + path: "./pages/java_api/java-api-com-nvidia-cuvs-spi-cuvsprovider.md" + - page: "Com Nvidia cuVS Spi Cuvsserviceprovider" + path: "./pages/java_api/java-api-com-nvidia-cuvs-spi-cuvsserviceprovider.md" + - section: "Rust API Documentation" + path: "./pages/rust_api/index.md" + contents: + - page: "cuVS Cluster" + path: "./pages/rust_api/rust-api-cuvs-cluster.md" + - page: "cuVS Cluster Kmeans" + path: "./pages/rust_api/rust-api-cuvs-cluster-kmeans.md" + - page: "cuVS Cluster Kmeans Params" + path: "./pages/rust_api/rust-api-cuvs-cluster-kmeans-params.md" + - page: "cuVS" + path: "./pages/rust_api/rust-api-cuvs.md" + - page: "cuVS Dlpack" + path: "./pages/rust_api/rust-api-cuvs-dlpack.md" + - page: "cuVS Error" + path: "./pages/rust_api/rust-api-cuvs-error.md" + - page: "cuVS Resources" + path: "./pages/rust_api/rust-api-cuvs-resources.md" + - page: "cuVS Distance" + path: "./pages/rust_api/rust-api-cuvs-distance.md" + - page: "cuVS Distance Type" + path: "./pages/rust_api/rust-api-cuvs-distance-type.md" + - page: "cuVS Brute Force" + path: "./pages/rust_api/rust-api-cuvs-brute-force.md" + - page: "cuVS Cagra" + path: "./pages/rust_api/rust-api-cuvs-cagra.md" + - page: "cuVS Cagra Index" + path: "./pages/rust_api/rust-api-cuvs-cagra-index.md" + - page: "cuVS Cagra Index Params" + path: "./pages/rust_api/rust-api-cuvs-cagra-index-params.md" + - page: "cuVS Cagra Search Params" + path: "./pages/rust_api/rust-api-cuvs-cagra-search-params.md" + - page: "cuVS IVF Flat" + path: "./pages/rust_api/rust-api-cuvs-ivf-flat.md" + - page: "cuVS IVF Flat Index" + path: "./pages/rust_api/rust-api-cuvs-ivf-flat-index.md" + - page: "cuVS IVF Flat Index Params" + path: "./pages/rust_api/rust-api-cuvs-ivf-flat-index-params.md" + - page: "cuVS IVF Flat Search Params" + path: "./pages/rust_api/rust-api-cuvs-ivf-flat-search-params.md" + - page: "cuVS IVF PQ" + path: "./pages/rust_api/rust-api-cuvs-ivf-pq.md" + - page: "cuVS IVF PQ Index" + path: "./pages/rust_api/rust-api-cuvs-ivf-pq-index.md" + - page: "cuVS IVF PQ Index Params" + path: "./pages/rust_api/rust-api-cuvs-ivf-pq-index-params.md" + - page: "cuVS IVF PQ Search Params" + path: "./pages/rust_api/rust-api-cuvs-ivf-pq-search-params.md" + - page: "cuVS Vamana" + path: "./pages/rust_api/rust-api-cuvs-vamana.md" + - page: "cuVS Vamana Index" + path: "./pages/rust_api/rust-api-cuvs-vamana-index.md" + - page: "cuVS Vamana Index Params" + path: "./pages/rust_api/rust-api-cuvs-vamana-index-params.md" + - section: "Go API Documentation" + path: "./pages/go_api/index.md" + contents: + - page: "Brute Force" + path: "./pages/go_api/go-api-brute-force.md" + - page: "Cagra" + path: "./pages/go_api/go-api-cagra.md" + - page: "cuVS" + path: "./pages/go_api/go-api-cuvs.md" + - page: "IVF Flat" + path: "./pages/go_api/go-api-ivf-flat.md" + - page: "IVF PQ" + path: "./pages/go_api/go-api-ivf-pq.md" diff --git a/fern/fern.config.json b/fern/fern.config.json new file mode 100644 index 0000000000..08c703bf54 --- /dev/null +++ b/fern/fern.config.json @@ -0,0 +1,4 @@ +{ + "organization": "nvidia", + "version": "*" +} diff --git a/fern/pages/advanced_topics.md b/fern/pages/advanced_topics.md new file mode 100644 index 0000000000..02bbdb61fe --- /dev/null +++ b/fern/pages/advanced_topics.md @@ -0,0 +1,13 @@ +--- +slug: developer-guide/advanced-topics +--- + +# Advanced Topics + +Use these pages when working on specialized cuVS development topics that need lower-level implementation context, runtime behavior, or platform-specific guidance. + +## Topic Guides + +- [ABI Stability](../developer_guide/abi_stability.md): understand ABI expectations for developer-facing APIs and downstream integrations. +- [JIT Compilation](jit_compilation.md): understand when cuVS triggers just-in-time compilation, how caches behave, and how to warm up JIT-compiled kernels. +- [Link-time Optimization](jit_lto_guide.md): use JIT LTO for CUDA compilation, fragment generation, and runtime linking workflows. diff --git a/fern/pages/api_basics.md b/fern/pages/api_basics.md new file mode 100644 index 0000000000..9350f65fc0 --- /dev/null +++ b/fern/pages/api_basics.md @@ -0,0 +1,80 @@ +# cuVS API Basics + +- [Memory management](#memory-management) +- [Resource management](#resource-management) + +## Memory management + +Centralized memory management allows flexible configuration of allocation strategies, such as sharing the same CUDA memory pool across library boundaries. cuVS uses the [RMM](https://github.com/rapidsai/rmm) library, which eases the burden of configuring different allocation strategies globally across GPU-accelerated libraries. + +RMM currently has APIs for C++ and Python. + +### C++ + +Here's an example of configuring RMM to use a pool allocator in C++ (derived from the RMM example [here](https://github.com/rapidsai/rmm?tab=readme-ov-file#example)): + +```c++ +rmm::mr::cuda_memory_resource cuda_mr; +// Construct a resource that uses a coalescing best-fit pool allocator +// With the pool initially half of available device memory +auto initial_size = rmm::percent_of_free_device_memory(50); +rmm::mr::pool_memory_resource pool_mr{cuda_mr, initial_size}; +rmm::mr::set_current_device_resource(pool_mr); +auto mr = rmm::mr::get_current_device_resource_ref(); +``` + +### Python + +And the corresponding code in Python (derived from the RMM example [here](https://github.com/rapidsai/rmm?tab=readme-ov-file#memoryresource-objects)): + +```python +import rmm +pool = rmm.mr.PoolMemoryResource( + rmm.mr.CudaMemoryResource(), + initial_pool_size=2**30, + maximum_pool_size=2**32) +rmm.mr.set_current_device_resource(pool) +``` + +## Resource management + +cuVS uses an API from the [RAFT](https://github.com/rapidsai/raft) library of ML and data mining primitives to centralize and reuse expensive resources, such as memory management. The below code examples demonstrate how to create these resources for use throughout this guide. + +See RAFT's [resource API documentation](https://docs.rapids.ai/api/raft/nightly/cpp_api/core_resources/) for more information. + +C +^ + +```c +#include +#include + +cuvsResources_t res; +cuvsResourcesCreate(&res); + +// ... do some processing ... + +cuvsResourcesDestroy(res); +``` + +### C++ + +```c++ +#include + +raft::device_resources res; +``` + +### Python + +```python +import pylibraft + +res = pylibraft.common.DeviceResources() +``` + +### Rust + +```rust +let res = cuvs::Resources::new()?; +``` diff --git a/fern/pages/api_docs.md b/fern/pages/api_docs.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/fern/pages/api_guide.md b/fern/pages/api_guide.md new file mode 100644 index 0000000000..e16f68a411 --- /dev/null +++ b/fern/pages/api_guide.md @@ -0,0 +1,37 @@ +--- +slug: user-guide/api-guides +--- + +# API Guide + +Use these pages to find task-focused cuVS API examples for clustering, vector indexing, preprocessing, and supporting routines. + +## Clustering Guide + +- [K-Means](cluster/kmeans.md): partition vectors into a fixed number of clusters, often as part of scalable vector-search systems. +- [Single-linkage](cluster/single_linkage.md): build hierarchical clusters from nearest-neighbor relationships. +- [Spectral Clustering](cluster/spectral.md): use graph structure and spectral methods to identify clusters with more complex shapes. + +## Indexing Guide + +- [Brute-force](neighbors/bruteforce.md): run exact nearest-neighbor search by comparing each query with every vector. +- [CAGRA](neighbors/cagra.md): build and search GPU-optimized graph indexes for high-throughput ANN search. +- [NN-Descent](neighbors/nn_descent.md): build approximate nearest-neighbor graphs with an iterative algorithm. +- [IVF-Flat](neighbors/ivfflat.md): partition vectors into inverted-file lists while storing full-precision vectors. +- [IVF-PQ](neighbors/ivfpq.md): combine inverted-file partitioning with product quantization for compact indexes. +- [ScaNN](neighbors/scann.md): combine partitioning, quantization, and refinement for high-quality approximate search. +- [Vamana](neighbors/vamana.md): build graph indexes for large-scale and disk-backed search workflows. +- [All-neighbors](neighbors/all_neighbors.md): compute all-neighbors graph structures. + +## Preprocessing Guide + +- [Binary Quantizer](preprocessing/binary_quantizer.md): compress vectors into binary representations for compact storage and fast comparisons. +- [PCA](preprocessing/pca.md): reduce dimensionality with a linear projection while preserving as much variance as possible. +- [Product Quantization](preprocessing/product_quantization.md): split vectors into subvectors and encode each part with compact codebooks. +- [Scalar Quantizer](preprocessing/scalar_quantizer.md): compress each vector dimension independently with scalar quantization. +- [Spectral Embedding](preprocessing/spectral_embedding.md): create lower-dimensional embeddings from graph structure. + +## Other APIs + +- [Pairwise Distances](other/pairwise_distances.md): compute distances between vectors for analysis, validation, or algorithm building blocks. +- [K-selection](other/select_k.md): select the top `k` values or nearest candidates from larger result sets. diff --git a/fern/pages/api_interoperability.md b/fern/pages/api_interoperability.md new file mode 100644 index 0000000000..82b6f880f8 --- /dev/null +++ b/fern/pages/api_interoperability.md @@ -0,0 +1,105 @@ +# Interoperability + +## DLPack (C) + +Approximate nearest neighbor (ANN) indexes provide an interface to build and search an index via a C API. [DLPack v0.8](https://github.com/dmlc/dlpack/blob/main/README.md), a tensor interface framework, is used as the standard to interact with our C API. + +Representing a tensor with DLPack is simple, as it is a POD struct that stores information about the tensor at runtime. At the moment, `DLManagedTensor` from DLPack v0.8 is compatible with out C API however we will soon upgrade to `DLManagedTensorVersioned` from DLPack v1.0 as it will help us maintain ABI and API compatibility. + +Here's an example on how to represent device memory using `DLManagedTensor`: + +```c +#include + +// Create data representation in host memory +float dataset[2][1] = {{0.2, 0.1}}; +// copy data to device memory +float *dataset_dev; +cuvsRMMAlloc(&dataset_dev, sizeof(float) * 2 * 1); +cudaMemcpy(dataset_dev, dataset, sizeof(float) * 2 * 1, cudaMemcpyDefault); + +// Use DLPack for representing the data as a tensor +DLManagedTensor dataset_tensor; +dataset_tensor.dl_tensor.data = dataset; +dataset_tensor.dl_tensor.device.device_type = kDLCUDA; +dataset_tensor.dl_tensor.ndim = 2; +dataset_tensor.dl_tensor.dtype.code = kDLFloat; +dataset_tensor.dl_tensor.dtype.bits = 32; +dataset_tensor.dl_tensor.dtype.lanes = 1; +int64_t dataset_shape[2] = {2, 1}; +dataset_tensor.dl_tensor.shape = dataset_shape; +dataset_tensor.dl_tensor.strides = nullptr; + +// free memory after use +cuvsRMMFree(dataset_dev); +``` + +Please refer to [cuVS C API documentation](/api-reference/c-api-documentation) to learn more. + +## Multi-dimensional span (C++) + +cuVS is built on top of the GPU-accelerated machine learning and data mining primitives in the [RAFT](https://github.com/rapidsai/raft) library. Most of the C++ APIs in cuVS accept [mdspan](https://arxiv.org/abs/2010.06474) multi-dimensional array view for representing data in higher dimensions similar to the `ndarray` in the Numpy Python library. RAFT also contains the corresponding owning `mdarray` structure, which simplifies the allocation and management of multi-dimensional data in both host and device (GPU) memory. + +The `mdarray` is an owning object that forms a convenience layer over RMM and can be constructed in RAFT using a number of different helper functions: + +```c++ +#include + +int n_rows = 10; +int n_cols = 10; + +auto scalar = raft::make_device_scalar(handle, 1.0); +auto vector = raft::make_device_vector(handle, n_cols); +auto matrix = raft::make_device_matrix(handle, n_rows, n_cols); +``` + +The `mdspan` is a lightweight non-owning view that can wrap around any pointer, maintaining shape, layout, and indexing information for accessing elements. + +We can construct `mdspan` instances directly from the above `mdarray` instances: + +```c++ +// Scalar mdspan on device +auto scalar_view = scalar.view(); + +// Vector mdspan on device +auto vector_view = vector.view(); + +// Matrix mdspan on device +auto matrix_view = matrix.view(); +``` + +Since the `mdspan` is just a lightweight wrapper, we can also construct it from the underlying data handles in the `mdarray` instances above. We use the extent to get information about the `mdarray` or `mdspan`'s shape. + +```c++ +#include + +auto scalar_view = raft::make_device_scalar_view(scalar.data_handle()); +auto vector_view = raft::make_device_vector_view(vector.data_handle(), vector.extent(0)); +auto matrix_view = raft::make_device_matrix_view(matrix.data_handle(), matrix.extent(0), matrix.extent(1)); +``` + +Of course, RAFT's `mdspan`/`mdarray` APIs aren't just limited to the `device`. You can also create `host` variants: + +```c++ +#include +#include + +int n_rows = 10; +int n_cols = 10; + +auto scalar = raft::make_host_scalar(handle, 1.0); +auto vector = raft::make_host_vector(handle, n_cols); +auto matrix = raft::make_host_matrix(handle, n_rows, n_cols); + +auto scalar_view = raft::make_host_scalar_view(scalar.data_handle()); +auto vector_view = raft::make_host_vector_view(vector.data_handle(), vector.extent(0)); +auto matrix_view = raft::make_host_matrix_view(matrix.data_handle(), matrix.extent(0), matrix.extent(1)); +``` + +Please refer to RAFT's [mdspan documentation](https://docs.rapids.ai/api/raft/stable/cpp_api/mdspan/) to learn more. + +## CUDA array interface (Python) + +The Python APIs accept objects that expose the CUDA Array Interface, which enables interoperability with GPU array libraries such as CuPy, Numba, PyTorch, and TensorFlow without copying device memory when compatible layouts are used. + +See [Using APIs in Python](working_with_ann_indexes.md#python) for examples of building and searching cuVS indexes from Python arrays. diff --git a/fern/pages/benchmarking_guide.md b/fern/pages/benchmarking_guide.md new file mode 100644 index 0000000000..f94e571c22 --- /dev/null +++ b/fern/pages/benchmarking_guide.md @@ -0,0 +1,10 @@ +--- +slug: user-guide/benchmarking-guide +--- + +# Benchmarking Guide + +Use these guides to compare vector-search algorithms fairly and run reproducible benchmark workflows with cuVS Bench. + +- [Methodologies](comparing_indexes.md): compare indexes using quality buckets, Pareto curves, and consistent build and search metrics. +- [cuVS Bench Tool](cuvs_bench/index.md): use cuVS Bench to run reproducible benchmark workflows, prepare datasets, and extend benchmark backends. diff --git a/fern/pages/build.md b/fern/pages/build.md new file mode 100644 index 0000000000..756b33a9eb --- /dev/null +++ b/fern/pages/build.md @@ -0,0 +1,60 @@ +# Installation + +NVIDIA cuVS provides APIs for C, C++, Python, Java, Go, and Rust. Start with the language you plan to use; each guide separates package installation from source builds and calls out any language-specific setup. + +All NVIDIA cuVS routine implementations live in the C++ core. For every non-C++ language binding, install both the C library (`libcuvs_c`) and the C++ library (`libcuvs`) unless the selected package explicitly bundles them. + +## CUDA GPU Requirements + +Pre-compiled NVIDIA cuVS packages are available for Linux on x86_64 and aarch64. Native Windows support is not available at this time. On Windows, use WSL2 with GPU passthrough. See the [RAPIDS WSL2 guide](https://rapids.ai/start.html#wsl2). + +Source builds and package installs require a supported NVIDIA GPU. For current source builds, use CUDA Toolkit 12.2 or newer and an Ampere architecture GPU or newer, which means compute capability 8.0 or higher. + +## Language Guides + +- [C](/installation/c): install or build the C API and `libcuvs_c`. +- [C++](/installation/cpp): install or build the C++ headers and `libcuvs`. +- [Python](/installation/python): install Python wheels or conda packages, or build the Python package from source. +- [Java](/installation/java): build the Java API and connect it to matching native cuVS libraries. +- [Go](/installation/go): install the Go module and configure CGO against native cuVS libraries. +- [Rust](/installation/rust): install the Rust crate and configure native cuVS dependencies. + +## Build From Source + +Most source builds use the repository `build.sh` script. The script wraps CMake, prepares install targets, and provides language-specific build targets. Each language guide shows the target most users need. + +The common source-build prerequisites are: + +1. CMake 3.26.4 or newer. +2. GCC 9.3 or newer, with GCC 11.4 or newer recommended. +3. CUDA Toolkit 12.2 or newer. +4. An Ampere architecture GPU or newer. + +### Create a Build Environment + +The recommended way to construct an environment with the dependencies required to build NVIDIA cuVS is to use conda with the repository environment YAML file: + +```bash +conda env create --name cuvs -f conda/environments/all_cuda-132_arch-$(uname -m).yaml +conda activate cuvs +``` + +You may prefer `mamba` over `conda` for faster environment solves. The `conda/environments` directory also contains language-specific environment YAML files for narrower development environments. Conda is not required, but if you do not use it, install all required build dependencies explicitly before running `build.sh`. + +## Documentation Preview + +The NVIDIA cuVS documentation is a Fern project in the repository's `fern` directory. Fern requires Node.js 22 or newer. If the docs fail with an error such as `SyntaxError: Unexpected token '.'`, check `node --version` and activate a newer Node.js runtime. + +Run the local preview from the repository root: + +```bash +fern/build_docs.sh dev +``` + +Fern serves the preview at [http://localhost:3000](http://localhost:3000) by default. + +Run the Fern checks before publishing documentation changes: + +```bash +fern/build_docs.sh check +``` diff --git a/fern/pages/c_api/c-api-cluster-kmeans.md b/fern/pages/c_api/c-api-cluster-kmeans.md new file mode 100644 index 0000000000..3df8abab07 --- /dev/null +++ b/fern/pages/c_api/c-api-cluster-kmeans.md @@ -0,0 +1,350 @@ +--- +slug: api-reference/c-api-cluster-kmeans +--- + +# K-Means + +_Source header: `cuvs/cluster/kmeans.h`_ + +## k-means hyperparameters + + +### cuvsKMeansInitMethod + +k-means hyperparameters + +```c +typedef enum { ... } cuvsKMeansInitMethod; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `KMeansPlusPlus` | `0` | +| `Random` | `1` | +| `Array` | `2` | + + +### cuvsKMeansParams + +Hyper-parameters for the kmeans algorithm + +NB: The inertia_check field is kept for ABI compatibility. Removed in cuvsKMeansParams_v2. TODO: CalVer for the replacement: 26.08 + +```c +struct cuvsKMeansParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_clusters` | `int` | The number of clusters to form as well as the number of centroids to generate (default:8). | +| `init` | [`cuvsKMeansInitMethod`](/api-reference/c-api-cluster-kmeans#cuvskmeansinitmethod) | Method for initialization, defaults to k-means++:
- cuvsKMeansInitMethod::KMeansPlusPlus (k-means++): Use scalable k-means++ algorithm to select the initial cluster centers.
- cuvsKMeansInitMethod::Random (random): Choose 'n_clusters' observations (rows) at random from the input data for the initial centroids.
- cuvsKMeansInitMethod::Array (ndarray): Use 'centroids' as initial cluster centers. | +| `max_iter` | `int` | Maximum number of iterations of the k-means algorithm for a single run. | +| `tol` | `double` | Relative tolerance with regards to inertia to declare convergence. | +| `n_init` | `int` | Number of instance k-means algorithm will be run with different seeds. | +| `oversampling_factor` | `double` | Oversampling factor for use in the k-means\|\| algorithm | +| `batch_samples` | `int` | batch_samples and batch_centroids are used to tile 1NN computation which is useful to optimize/control the memory footprint Default tile is [batch_samples x n_clusters] i.e. when batch_centroids is 0 then don't tile the centroids | +| `batch_centroids` | `int` | if 0 then batch_centroids = n_clusters | +| `inertia_check` | `bool` | Deprecated, ignored. Kept for ABI compatibility. | +| `hierarchical` | `bool` | Whether to use hierarchical (balanced) kmeans or not | +| `hierarchical_n_iters` | `int` | For hierarchical k-means , defines the number of training iterations | +| `streaming_batch_size` | `int64_t` | Number of samples to process per GPU batch for the batched (host-data) API. When set to 0, defaults to n_samples (process all at once). | +| `init_size` | `int64_t` | Number of samples to draw for KMeansPlusPlus initialization. When set to 0, uses heuristic min(3 * n_clusters, n_samples) for host data, or n_samples for device data. | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | | + + +### cuvsKMeansParams_v2 + +Hyper-parameters for the kmeans algorithm + +TODO: Remove this after cuvsKMeansParams is replaced in ABI 2.0 + +```c +struct cuvsKMeansParams_v2 { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_clusters` | `int` | The number of clusters to form as well as the number of centroids to generate (default:8). | +| `init` | [`cuvsKMeansInitMethod`](/api-reference/c-api-cluster-kmeans#cuvskmeansinitmethod) | Method for initialization, defaults to k-means++:
- cuvsKMeansInitMethod::KMeansPlusPlus (k-means++): Use scalable k-means++ algorithm to select the initial cluster centers.
- cuvsKMeansInitMethod::Random (random): Choose 'n_clusters' observations (rows) at random from the input data for the initial centroids.
- cuvsKMeansInitMethod::Array (ndarray): Use 'centroids' as initial cluster centers. | +| `max_iter` | `int` | Maximum number of iterations of the k-means algorithm for a single run. | +| `tol` | `double` | Relative tolerance with regards to inertia to declare convergence. | +| `n_init` | `int` | Number of instance k-means algorithm will be run with different seeds. | +| `oversampling_factor` | `double` | Oversampling factor for use in the k-means\|\| algorithm | +| `batch_samples` | `int` | batch_samples and batch_centroids are used to tile 1NN computation which is useful to optimize/control the memory footprint Default tile is [batch_samples x n_clusters] i.e. when batch_centroids is 0 then don't tile the centroids | +| `batch_centroids` | `int` | if 0 then batch_centroids = n_clusters | +| `hierarchical` | `bool` | Whether to use hierarchical (balanced) kmeans or not | +| `hierarchical_n_iters` | `int` | For hierarchical k-means , defines the number of training iterations | +| `streaming_batch_size` | `int64_t` | Number of samples to process per GPU batch for the batched (host-data) API. When set to 0, defaults to n_samples (process all at once). | +| `init_size` | `int64_t` | Number of samples to draw for KMeansPlusPlus initialization. When set to 0, uses heuristic min(3 * n_clusters, n_samples) for host data, or n_samples for device data. | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | | + + +### cuvsKMeansParamsCreate + +Allocate KMeans params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansParamsCreate(cuvsKMeansParams_t* params); +``` + +replaced by cuvsKMeansParamsCreate_v2. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsKMeansParams_t*`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams) | cuvsKMeansParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansParamsDestroy + +De-allocate KMeans params + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansParamsDestroy(cuvsKMeansParams_t params); +``` + +replaced by cuvsKMeansParamsDestroy_v2. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsKMeansParams_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansParamsCreate_v2 + +Allocate KMeans params + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansParamsCreate_v2(cuvsKMeansParams_v2_t* params); +``` + +Mirrors cuvsKMeansParamsCreate but operates on cuvsKMeansParams_v2. Will become the unsuffixed cuvsKMeansParamsCreate in cuVS 26.08. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsKMeansParams_v2_t*`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams-v2) | cuvsKMeansParams_v2_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansParamsDestroy_v2 + +De-allocate KMeans params allocated by cuvsKMeansParamsCreate_v2. + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansParamsDestroy_v2(cuvsKMeansParams_v2_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsKMeansParams_v2_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams-v2) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansType + +Type of k-means algorithm. + +```c +typedef enum { ... } cuvsKMeansType; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_KMEANS_TYPE_KMEANS` | `0` | +| `CUVS_KMEANS_TYPE_KMEANS_BALANCED` | `1` | + +## k-means clustering APIs + + +### cuvsKMeansFit + +Find clusters with k-means algorithm. + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansFit(cuvsResources_t res, +cuvsKMeansParams_t params, +DLManagedTensor* X, +DLManagedTensor* sample_weight, +DLManagedTensor* centroids, +double* inertia, +int* n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +X may reside on either host (CPU) or device (GPU) memory. When X is on the host the data is streamed to the GPU in batches controlled by params->streaming_batch_size. + +replaced by cuvsKMeansFit_v2. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | opaque C handle | +| `params` | in | [`cuvsKMeansParams_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams) | Parameters for KMeans model. | +| `X` | in | `DLManagedTensor*` | Training instances to cluster. The data must be in row-major format. May be on host or device memory. [dim = n_samples x n_features] | +| `sample_weight` | in | `DLManagedTensor*` | Optional weights for each observation in X. Must be on the same memory space as X. [len = n_samples] | +| `centroids` | inout | `DLManagedTensor*` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. Must be on device. [dim = n_clusters x n_features] | +| `inertia` | out | `double*` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `int*` | Number of iterations run. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansFit_v2 + +Find clusters with k-means algorithm (v2 params layout). + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansFit_v2(cuvsResources_t res, +cuvsKMeansParams_v2_t params, +DLManagedTensor* X, +DLManagedTensor* sample_weight, +DLManagedTensor* centroids, +double* inertia, +int* n_iter); +``` + +Mirrors cuvsKMeansFit but takes cuvsKMeansParams_v2_t. Will become the unsuffixed cuvsKMeansFit in cuVS 26.08. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | opaque C handle | +| `params` | in | [`cuvsKMeansParams_v2_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams-v2) | Parameters for KMeans model (v2 layout). | +| `X` | in | `DLManagedTensor*` | Training instances to cluster. The data must be in row-major format. May be on host or device memory. [dim = n_samples x n_features] | +| `sample_weight` | in | `DLManagedTensor*` | Optional weights for each observation in X. Must be on the same memory space as X. [len = n_samples] | +| `centroids` | inout | `DLManagedTensor*` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. Must be on device. [dim = n_clusters x n_features] | +| `inertia` | out | `double*` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `int*` | Number of iterations run. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansPredict + +Predict the closest cluster each sample in X belongs to. + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansPredict(cuvsResources_t res, +cuvsKMeansParams_t params, +DLManagedTensor* X, +DLManagedTensor* sample_weight, +DLManagedTensor* centroids, +DLManagedTensor* labels, +bool normalize_weight, +double* inertia); +``` + +replaced by cuvsKMeansPredict_v2. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | opaque C handle | +| `params` | in | [`cuvsKMeansParams_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams) | Parameters for KMeans model. | +| `X` | in | `DLManagedTensor*` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `DLManagedTensor*` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `DLManagedTensor*` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `DLManagedTensor*` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `double*` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansPredict_v2 + +Predict the closest cluster each sample in X belongs to (v2 params layout). + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansPredict_v2(cuvsResources_t res, +cuvsKMeansParams_v2_t params, +DLManagedTensor* X, +DLManagedTensor* sample_weight, +DLManagedTensor* centroids, +DLManagedTensor* labels, +bool normalize_weight, +double* inertia); +``` + +Mirrors cuvsKMeansPredict but takes cuvsKMeansParams_v2_t. Will become the unsuffixed cuvsKMeansPredict in cuVS 26.08. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | opaque C handle | +| `params` | in | [`cuvsKMeansParams_v2_t`](/api-reference/c-api-cluster-kmeans#cuvskmeansparams-v2) | Parameters for KMeans model (v2 layout). | +| `X` | in | `DLManagedTensor*` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `DLManagedTensor*` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `DLManagedTensor*` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `DLManagedTensor*` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `double*` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsKMeansClusterCost + +Compute cluster cost + +```c +CUVS_EXPORT cuvsError_t cuvsKMeansClusterCost(cuvsResources_t res, +DLManagedTensor* X, +DLManagedTensor* centroids, +double* cost); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | opaque C handle | +| `X` | in | `DLManagedTensor*` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | in | `DLManagedTensor*` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `cost` | out | `double*` | Resulting cluster cost | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-core-c-api.md b/fern/pages/c_api/c-api-core-c-api.md new file mode 100644 index 0000000000..7fa3de0f0c --- /dev/null +++ b/fern/pages/c_api/c-api-core-c-api.md @@ -0,0 +1,523 @@ +--- +slug: api-reference/c-api-core-c-api +--- + +# C API + +_Source header: `cuvs/core/c_api.h`_ + +## cuVS Error Messages + + +### cuvsError_t + +An enum denoting error statuses for function calls + +```c +typedef enum { ... } cuvsError_t; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_ERROR` | `0` | +| `CUVS_SUCCESS` | `1` | + + +### cuvsGetLastErrorText + +Returns a string describing the last seen error on this thread, or + +```c +CUVS_EXPORT const char* cuvsGetLastErrorText(); +``` + +NULL if the last function succeeded. + +**Returns** + +`CUVS_EXPORT const char*` + + +### cuvsSetLastErrorText + +Sets a string describing an error seen on the thread. Passing NULL + +```c +CUVS_EXPORT void cuvsSetLastErrorText(const char* error); +``` + +clears any previously seen error message. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `error` | | `const char*` | | + +**Returns** + +`CUVS_EXPORT void` + +## cuVS Logging + + +### cuvsLogLevel_t + +An enum denoting log levels + +```c +typedef enum { ... } cuvsLogLevel_t; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_LOG_LEVEL_TRACE` | `0` | +| `CUVS_LOG_LEVEL_DEBUG` | `1` | +| `CUVS_LOG_LEVEL_INFO` | `2` | +| `CUVS_LOG_LEVEL_WARN` | `3` | +| `CUVS_LOG_LEVEL_ERROR` | `4` | +| `CUVS_LOG_LEVEL_CRITICAL` | `5` | +| `CUVS_LOG_LEVEL_OFF` | `6` | + + +### cuvsGetLogLevel + +Returns the current log level + +```c +CUVS_EXPORT cuvsLogLevel_t cuvsGetLogLevel(); +``` + +**Returns** + +[`CUVS_EXPORT cuvsLogLevel_t`](/api-reference/c-api-core-c-api#cuvsloglevel-t) + + +### cuvsSetLogLevel + +Sets the log level + +```c +CUVS_EXPORT void cuvsSetLogLevel(cuvsLogLevel_t); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `arg1` | | [`cuvsLogLevel_t`](/api-reference/c-api-core-c-api#cuvsloglevel-t) | | + +**Returns** + +`CUVS_EXPORT void` + +## cuVS Resources Handle + + +### cuvsResources_t + +An opaque C handle for C++ type `raft::resources` + +```c +typedef uintptr_t cuvsResources_t; +``` + + +### cuvsResourcesCreate + +Create an Initialized opaque C handle for C++ type `raft::resources` + +```c +CUVS_EXPORT cuvsError_t cuvsResourcesCreate(cuvsResources_t* res); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t*`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsResourcesDestroy + +Destroy and de-allocate opaque C handle for C++ type `raft::resources` + +```c +CUVS_EXPORT cuvsError_t cuvsResourcesDestroy(cuvsResources_t res); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsStreamSet + +Set cudaStream_t on cuvsResources_t to queue CUDA kernels on APIs + +```c +CUVS_EXPORT cuvsError_t cuvsStreamSet(cuvsResources_t res, cudaStream_t stream); +``` + +that accept a cuvsResources_t handle + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `stream` | in | `cudaStream_t` | cudaStream_t stream to queue CUDA kernels | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsStreamGet + +Get the cudaStream_t from a cuvsResources_t + +```c +CUVS_EXPORT cuvsError_t cuvsStreamGet(cuvsResources_t res, cudaStream_t* stream); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `stream` | out | `cudaStream_t*` | cudaStream_t stream to queue CUDA kernels | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsStreamSync + +Syncs the current CUDA stream on the resources object + +```c +CUVS_EXPORT cuvsError_t cuvsStreamSync(cuvsResources_t res); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsDeviceIdGet + +Get the id of the device associated with this cuvsResources_t + +```c +CUVS_EXPORT cuvsError_t cuvsDeviceIdGet(cuvsResources_t res, int* device_id); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `device_id` | out | `int*` | int the id of the device associated with res | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuResourcesCreate + +Create an Initialized opaque C handle for C++ type `raft::device_resources_snmg` + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuResourcesCreate(cuvsResources_t* res); +``` + +for multi-GPU operations + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t*`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuResourcesCreateWithDeviceIds + +Create an Initialized opaque C handle for C++ type `raft::device_resources_snmg` + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuResourcesCreateWithDeviceIds(cuvsResources_t* res, +DLManagedTensor* device_ids); +``` + +for multi-GPU operations with specific device IDs + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t*`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `device_ids` | in | `DLManagedTensor*` | DLManagedTensor* containing device IDs to use | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuResourcesDestroy + +Destroy and de-allocate opaque C handle for C++ type `raft::device_resources_snmg` + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuResourcesDestroy(cuvsResources_t res); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuResourcesSetMemoryPool + +Set a memory pool on all devices managed by the multi-GPU resources + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuResourcesSetMemoryPool(cuvsResources_t res, int percent_of_free_memory); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle for multi-GPU resources | +| `percent_of_free_memory` | in | `int` | Percent of free memory to allocate for the pool | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## cuVS Memory Allocation + + +### cuvsRMMAlloc + +Allocates device memory using RMM + +```c +CUVS_EXPORT cuvsError_t cuvsRMMAlloc(cuvsResources_t res, void** ptr, size_t bytes); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `ptr` | out | `void**` | Pointer to allocated device memory | +| `bytes` | in | `size_t` | Size in bytes to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsRMMFree + +Deallocates device memory using RMM + +```c +CUVS_EXPORT cuvsError_t cuvsRMMFree(cuvsResources_t res, void* ptr, size_t bytes); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `ptr` | in | `void*` | Pointer to allocated device memory to free | +| `bytes` | in | `size_t` | Size in bytes to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsRMMPoolMemoryResourceEnable + +Switches the working memory resource to use the RMM pool memory resource, which will + +```c +CUVS_EXPORT cuvsError_t cuvsRMMPoolMemoryResourceEnable(int initial_pool_size_percent, +int max_pool_size_percent, +bool managed); +``` + +bypass unnecessary synchronizations by allocating a chunk of device memory up front and carving that up for temporary memory allocations within algorithms. Be aware that this function will change the memory resource for the whole process and the new memory resource will be used until explicitly changed. + +available memory available memory + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `initial_pool_size_percent` | in | `int` | The initial pool size as a percentage of the total | +| `max_pool_size_percent` | in | `int` | The maximum pool size as a percentage of the total | +| `managed` | in | `bool` | Whether to use a managed memory resource as upstream resource or not | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsRMMMemoryResourceReset + +Resets the memory resource to use the default memory resource (cuda_memory_resource) + +```c +CUVS_EXPORT cuvsError_t cuvsRMMMemoryResourceReset(); +``` + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsRMMHostAlloc + +Allocates pinned memory on the host using RMM + +```c +CUVS_EXPORT cuvsError_t cuvsRMMHostAlloc(void** ptr, size_t bytes); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `ptr` | out | `void**` | Pointer to allocated host memory | +| `bytes` | in | `size_t` | Size in bytes to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsRMMHostFree + +Deallocates pinned memory on the host using RMM + +```c +CUVS_EXPORT cuvsError_t cuvsRMMHostFree(void* ptr, size_t bytes); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `ptr` | in | `void*` | Pointer to allocated host memory to free | +| `bytes` | in | `size_t` | Size in bytes to deallocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsVersionGet + +Get the version of the cuVS library + +```c +CUVS_EXPORT cuvsError_t cuvsVersionGet(uint16_t* major, uint16_t* minor, uint16_t* patch); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `major` | out | `uint16_t*` | Major version | +| `minor` | out | `uint16_t*` | Minor version | +| `patch` | out | `uint16_t*` | Patch version | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMatrixCopy + +Copy a matrix + +```c +CUVS_EXPORT cuvsError_t cuvsMatrixCopy(cuvsResources_t res, DLManagedTensor* src, DLManagedTensor* dst); +``` + +This function copies a matrix from dst to src. This lets you copy a matrix from device memory to host memory (or vice versa), while accounting for differences in strides. + +Both src and dst must have the same shape and dtype, but can have different strides and device type. The memory for the output dst tensor must already be allocated and the tensor initialized. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `src` | in | `DLManagedTensor*` | Pointer to DLManagedTensor to copy | +| `dst` | out | `DLManagedTensor*` | Pointer to DLManagedTensor to receive copy of data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMatrixSliceRows + +Slices rows from a matrix + +```c +CUVS_EXPORT cuvsError_t cuvsMatrixSliceRows( +cuvsResources_t res, DLManagedTensor* src, int64_t start, int64_t end, DLManagedTensor* dst); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `src` | in | `DLManagedTensor*` | Pointer to DLManagedTensor to copy | +| `start` | in | `int64_t` | First row index to include in the output | +| `end` | in | `int64_t` | Last row index to include in the output | +| `dst` | out | `DLManagedTensor*` | Pointer to DLManagedTensor to receive slice from matrix | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-distance-distance.md b/fern/pages/c_api/c-api-distance-distance.md new file mode 100644 index 0000000000..9774f2fac0 --- /dev/null +++ b/fern/pages/c_api/c-api-distance-distance.md @@ -0,0 +1,43 @@ +--- +slug: api-reference/c-api-distance-distance +--- + +# Distance + +_Source header: `cuvs/distance/distance.h`_ + +## Types + + +### cuvsDistanceType + +enum to tell how to compute distance + +```c +typedef enum { ... } cuvsDistanceType; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `L2Expanded` | `0` | +| `CosineExpanded` | `2` | +| `L1` | `3` | +| `L2Unexpanded` | `4` | +| `InnerProduct` | `6` | +| `Linf` | `7` | +| `Canberra` | `8` | +| `LpUnexpanded` | `9` | +| `CorrelationExpanded` | `10` | +| `JaccardExpanded` | `11` | +| `HellingerExpanded` | `12` | +| `Haversine` | `13` | +| `BrayCurtis` | `14` | +| `JensenShannon` | `15` | +| `HammingUnexpanded` | `16` | +| `KLDivergence` | `17` | +| `RusselRaoExpanded` | `18` | +| `DiceExpanded` | `19` | +| `BitwiseHamming` | `20` | +| `Precomputed` | `100` | diff --git a/fern/pages/c_api/c-api-distance-pairwise-distance.md b/fern/pages/c_api/c-api-distance-pairwise-distance.md new file mode 100644 index 0000000000..daeed917f8 --- /dev/null +++ b/fern/pages/c_api/c-api-distance-pairwise-distance.md @@ -0,0 +1,40 @@ +--- +slug: api-reference/c-api-distance-pairwise-distance +--- + +# Pairwise Distance + +_Source header: `cuvs/distance/pairwise_distance.h`_ + +## C pairwise distance + + +### cuvsPairwiseDistance + +Compute pairwise distances for two matrices + +```c +CUVS_EXPORT cuvsError_t cuvsPairwiseDistance(cuvsResources_t res, +DLManagedTensor* x, +DLManagedTensor* y, +DLManagedTensor* dist, +cuvsDistanceType metric, +float metric_arg); +``` + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvs resources object for managing expensive resources | +| `x` | in | `DLManagedTensor*` | first set of points (size n*k) | +| `y` | in | `DLManagedTensor*` | second set of points (size m*k) | +| `dist` | out | `DLManagedTensor*` | output distance matrix (size n*m) | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | distance to evaluate | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-all-neighbors.md b/fern/pages/c_api/c-api-neighbors-all-neighbors.md new file mode 100644 index 0000000000..22da7eb0ac --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-all-neighbors.md @@ -0,0 +1,119 @@ +--- +slug: api-reference/c-api-neighbors-all-neighbors +--- + +# All Neighbors + +_Source header: `cuvs/neighbors/all_neighbors.h`_ + +## All-neighbors C-API build parameters + + +### cuvsAllNeighborsAlgo + +Graph build algorithm selection. + +```c +typedef enum { ... } cuvsAllNeighborsAlgo; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_ALL_NEIGHBORS_ALGO_BRUTE_FORCE` | `0` | +| `CUVS_ALL_NEIGHBORS_ALGO_IVF_PQ` | `1` | +| `CUVS_ALL_NEIGHBORS_ALGO_NN_DESCENT` | `2` | + + +### cuvsAllNeighborsIndexParams + +Parameters controlling SNMG all-neighbors build. + +```c +struct cuvsAllNeighborsIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `algo` | [`cuvsAllNeighborsAlgo`](/api-reference/c-api-neighbors-all-neighbors#cuvsallneighborsalgo) | | +| `overlap_factor` | `size_t` | | +| `n_clusters` | `size_t` | | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | | +| `ivf_pq_params` | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | | +| `nn_descent_params` | [`cuvsNNDescentIndexParams_t`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindexparams) | | + + +### cuvsAllNeighborsIndexParamsCreate + +Create a default all-neighbors index parameters struct. + +```c +CUVS_EXPORT cuvsError_t cuvsAllNeighborsIndexParamsCreate(cuvsAllNeighborsIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | out | [`cuvsAllNeighborsIndexParams_t*`](/api-reference/c-api-neighbors-all-neighbors#cuvsallneighborsindexparams) | Pointer to allocated index_params struct | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsAllNeighborsIndexParamsDestroy + +Destroy an all-neighbors index parameters struct. + +```c +CUVS_EXPORT cuvsError_t cuvsAllNeighborsIndexParamsDestroy(cuvsAllNeighborsIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsAllNeighborsIndexParams_t`](/api-reference/c-api-neighbors-all-neighbors#cuvsallneighborsindexparams) | Index parameters struct to destroy | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## All-neighbors C-API build + + +### cuvsAllNeighborsBuild + +Build an all-neighbors k-NN graph automatically detecting host vs device dataset. + +```c +CUVS_EXPORT cuvsError_t cuvsAllNeighborsBuild(cuvsResources_t res, +cuvsAllNeighborsIndexParams_t params, +DLManagedTensor* dataset, +DLManagedTensor* indices, +DLManagedTensor* distances, +DLManagedTensor* core_distances, +float alpha); +``` + +resources The function automatically detects whether the dataset is host-resident or device-resident and calls the appropriate implementation. For host datasets, it partitions data into `n_clusters` clusters and assigns each row to `overlap_factor` nearest clusters. For device datasets, `n_clusters` must be 1 (no batching); `overlap_factor` is ignored. Outputs always reside in device memory. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | Can be a SNMG multi-GPU resources (`cuvsResources_t`) or single-GPU | +| `params` | in | [`cuvsAllNeighborsIndexParams_t`](/api-reference/c-api-neighbors-all-neighbors#cuvsallneighborsindexparams) | Build parameters (see cuvsAllNeighborsIndexParams) | +| `dataset` | in | `DLManagedTensor*` | 2D tensor [num_rows x dim] on host or device (auto-detected) | +| `indices` | out | `DLManagedTensor*` | 2D tensor [num_rows x k] on device (int64) | +| `distances` | out | `DLManagedTensor*` | Optional 2D tensor [num_rows x k] on device (float32); can be NULL | +| `core_distances` | out | `DLManagedTensor*` | Optional 1D tensor [num_rows] on device (float32); can be NULL | +| `alpha` | in | `float` | Mutual-reachability scaling; used only when core_distances is provided | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-brute-force.md b/fern/pages/c_api/c-api-neighbors-brute-force.md new file mode 100644 index 0000000000..f0973906dc --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-brute-force.md @@ -0,0 +1,186 @@ +--- +slug: api-reference/c-api-neighbors-brute-force +--- + +# Brute Force + +_Source header: `cuvs/neighbors/brute_force.h`_ + +## Bruteforce index + + +### cuvsBruteForceIndex + +Struct to hold address of cuvs::neighbors::brute_force::index and its active trained dtype + +```c +typedef struct { ... } cuvsBruteForceIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsBruteForceIndexCreate + +Allocate BRUTEFORCE index + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceIndexCreate(cuvsBruteForceIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsBruteForceIndex_t*`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | cuvsBruteForceIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBruteForceIndexDestroy + +De-allocate BRUTEFORCE index + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceIndexDestroy(cuvsBruteForceIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsBruteForceIndex_t`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | cuvsBruteForceIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Bruteforce index build + + +### cuvsBruteForceBuild + +Build a BRUTEFORCE index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceBuild(cuvsResources_t res, +DLManagedTensor* dataset, +cuvsDistanceType metric, +float metric_arg, +cuvsBruteForceIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | metric | +| `metric_arg` | in | `float` | metric_arg | +| `index` | out | [`cuvsBruteForceIndex_t`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | cuvsBruteForceIndex_t Newly built BRUTEFORCE index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Bruteforce index search + + +### cuvsBruteForceSearch + +Search a BRUTEFORCE index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceSearch(cuvsResources_t res, +cuvsBruteForceIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances, +cuvsFilter prefilter); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`. It is also important to note that the BRUTEFORCE index must have been built with the same type of `queries`, such that `index.dtype.code == queries.dl_tensor.dtype.code` Types for input are: + +1. `queries`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` or `kDLDataType.bits = 16` +2. `neighbors`: `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 32` +3. `distances`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in | [`cuvsBruteForceIndex_t`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | cuvsBruteForceIndex which has been returned by `cuvsBruteForceBuild` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | +| `prefilter` | in | [`cuvsFilter`](/api-reference/c-api-neighbors-common#cuvsfilter) | cuvsFilter input prefilter that can be used to filter queries and neighbors based on the given bitmap. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## BRUTEFORCE C-API serialize functions + + +### cuvsBruteForceSerialize + +Save the index to file. + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceSerialize(cuvsResources_t res, +const char* filename, +cuvsBruteForceIndex_t index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file name for saving the index | +| `index` | in | [`cuvsBruteForceIndex_t`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | BRUTEFORCE index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBruteForceDeserialize + +Load index from file. + +```c +CUVS_EXPORT cuvsError_t cuvsBruteForceDeserialize(cuvsResources_t res, +const char* filename, +cuvsBruteForceIndex_t index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the name of the file that stores the index | +| `index` | out | [`cuvsBruteForceIndex_t`](/api-reference/c-api-neighbors-brute-force#cuvsbruteforceindex) | BRUTEFORCE index loaded disk | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-cagra.md b/fern/pages/c_api/c-api-neighbors-cagra.md new file mode 100644 index 0000000000..264747fe6e --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-cagra.md @@ -0,0 +1,829 @@ +--- +slug: api-reference/c-api-neighbors-cagra +--- + +# Cagra + +_Source header: `cuvs/neighbors/cagra.h`_ + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraGraphBuildAlgo + +Enum to denote which ANN algorithm is used to build CAGRA graph + +```c +enum cuvsCagraGraphBuildAlgo { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `AUTO_SELECT` | `0` | +| `IVF_PQ` | `1` | + + +### cuvsCagraHnswHeuristicType + +A strategy for selecting the graph build parameters based on similar HNSW index + +parameters. + +Define how cuvsCagraIndexParamsFromHnswParams should construct a graph to construct a graph that is to be converted to (used by) a CPU HNSW index. + +```c +enum cuvsCagraHnswHeuristicType { ... }; +``` + + +### cuvsCagraCompressionParams + +Parameters for VPQ compression. + +```c +struct cuvsCagraCompressionParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `pq_bits` | `uint32_t` | The bit length of the vector element after compression by PQ. Possible values: [4, 5, 6, 7, 8]. Hint: the smaller the 'pq_bits', the smaller the index size and the better the search performance, but the lower the recall. | +| `pq_dim` | `uint32_t` | The dimensionality of the vector after compression by PQ. When zero, an optimal value is selected using a heuristic. TODO: at the moment `dim` must be a multiple `pq_dim`. | +| `vq_n_centers` | `uint32_t` | Vector Quantization (VQ) codebook size - number of "coarse cluster centers". When zero, an optimal value is selected using a heuristic. | +| `kmeans_n_iters` | `uint32_t` | The number of iterations searching for kmeans centers (both VQ & PQ phases). | +| `vq_kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building (VQ phase). When zero, an optimal value is selected using a heuristic. | +| `pq_kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building (PQ phase). When zero, an optimal value is selected using a heuristic. | + + +### cuvsAceParams + +Parameters for ACE (Augmented Core Extraction) graph build. + +ACE enables building indexes for datasets too large to fit in GPU memory by: + +1. Partitioning the dataset in core (closest) and augmented (second-closest) partitions using balanced k-means. +2. Building sub-indexes for each partition independently +3. Concatenating sub-graphs into a final unified index + +```c +struct cuvsAceParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `npartitions` | `size_t` | Number of partitions for ACE (Augmented Core Extraction) partitioned build. When set to 0 (default), the number of partitions is automatically derived based on available host and GPU memory to maximize partition size while ensuring the build fits in memory. Small values might improve recall but potentially degrade performance and increase memory usage. Partitions should not be too small to prevent issues in KNN graph construction. The partition size is on average 2 * (n_rows / npartitions) * dim * sizeof(T). 2 is because of the core and augmented vectors. Please account for imbalance in the partition sizes (up to 3x in our tests). If the specified number of partitions results in partitions that exceed available memory, the value will be automatically increased to fit memory constraints and a warning will be issued. | +| `ef_construction` | `size_t` | The index quality for the ACE build. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. | +| `build_dir` | `const char*` | Directory to store ACE build artifacts (e.g., KNN graph, optimized graph). Used when `use_disk` is true or when the graph does not fit in host and GPU memory. This should be the fastest disk in the system and hold enough space for twice the dataset, final graph, and label mapping. | +| `use_disk` | `bool` | Whether to use disk-based storage for ACE build. When true, enables disk-based operations for memory-efficient graph construction. | +| `max_host_memory_gb` | `double` | Maximum host memory to use for ACE build in GiB. When set to 0 (default), uses available host memory. When set to a positive value, limits host memory usage to the specified amount. Useful for testing or when running alongside other memory-intensive processes. | +| `max_gpu_memory_gb` | `double` | Maximum GPU memory to use for ACE build in GiB. When set to 0 (default), uses available GPU memory. When set to a positive value, limits GPU memory usage to the specified amount. Useful for testing or when running alongside other memory-intensive processes. | + + +### cuvsCagraIndexParams + +Supplemental parameters to build CAGRA Index + +```c +struct cuvsCagraIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance type. | +| `intermediate_graph_degree` | `size_t` | Degree of input graph for pruning. | +| `graph_degree` | `size_t` | Degree of output graph. | +| `build_algo` | [`enum cuvsCagraGraphBuildAlgo`](/api-reference/c-api-neighbors-cagra#cuvscagragraphbuildalgo) | ANN algorithm to build knn graph. | +| `nn_descent_niter` | `size_t` | Number of Iterations to run if building with NN_DESCENT | +| `compression` | [`cuvsCagraCompressionParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagracompressionparams) | Optional: specify compression parameters if compression is desired. NOTE: this is experimental new API, consider it unsafe. | +| `graph_build_params` | `void*` | Optional: specify graph build params based on build_algo
- IVF_PQ: cuvsIvfPqParams_t
- ACE: cuvsAceParams_t
- Others: nullptr | + + +### cuvsCagraIndexParamsCreate + +Allocate CAGRA Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexParamsCreate(cuvsCagraIndexParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraIndexParams_t*`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | cuvsCagraIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexParamsDestroy + +De-allocate CAGRA Index params + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexParamsDestroy(cuvsCagraIndexParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraCompressionParamsCreate + +Allocate CAGRA Compression params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsCagraCompressionParamsCreate(cuvsCagraCompressionParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraCompressionParams_t*`](/api-reference/c-api-neighbors-cagra#cuvscagracompressionparams) | cuvsCagraCompressionParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraCompressionParamsDestroy + +De-allocate CAGRA Compression params + +```c +CUVS_EXPORT cuvsError_t cuvsCagraCompressionParamsDestroy(cuvsCagraCompressionParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraCompressionParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagracompressionparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsAceParamsCreate + +Allocate ACE params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsAceParamsCreate(cuvsAceParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsAceParams_t*`](/api-reference/c-api-neighbors-cagra#cuvsaceparams) | cuvsAceParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsAceParamsDestroy + +De-allocate ACE params + +```c +CUVS_EXPORT cuvsError_t cuvsAceParamsDestroy(cuvsAceParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsAceParams_t`](/api-reference/c-api-neighbors-cagra#cuvsaceparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexParamsFromHnswParams + +Create CAGRA index parameters similar to an HNSW index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexParamsFromHnswParams(cuvsCagraIndexParams_t params, +int64_t n_rows, +int64_t dim, +int M, +int ef_construction, +enum cuvsCagraHnswHeuristicType heuristic, +cuvsDistanceType metric); +``` + +This factory function creates CAGRA parameters that yield a graph compatible with an HNSW graph with the given parameters. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | out | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | The CAGRA index params to populate | +| `n_rows` | in | `int64_t` | Number of rows in the dataset | +| `dim` | in | `int64_t` | Number of dimensions in the dataset | +| `M` | in | `int` | HNSW index parameter M | +| `ef_construction` | in | `int` | HNSW index parameter ef_construction | +| `heuristic` | in | [`enum cuvsCagraHnswHeuristicType`](/api-reference/c-api-neighbors-cagra#cuvscagrahnswheuristictype) | Strategy for parameter selection | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance metric to use | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraExtendParams + +Supplemental parameters to extend CAGRA Index + +```c +struct cuvsCagraExtendParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `max_chunk_size` | `uint32_t` | The additional dataset is divided into chunks and added to the graph. This is the knob to adjust the tradeoff between the recall and operation throughput. Large chunk sizes can result in high throughput, but use more working memory (O(max_chunk_size*degree^2)). This can also degrade recall because no edges are added between the nodes in the same chunk. Auto select when 0. | + + +### cuvsCagraExtendParamsCreate + +Allocate CAGRA Extend params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsCagraExtendParamsCreate(cuvsCagraExtendParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraExtendParams_t*`](/api-reference/c-api-neighbors-cagra#cuvscagraextendparams) | cuvsCagraExtendParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraExtendParamsDestroy + +De-allocate CAGRA Extend params + +```c +CUVS_EXPORT cuvsError_t cuvsCagraExtendParamsDestroy(cuvsCagraExtendParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraExtendParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraextendparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraExtend + +Extend a CAGRA index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsCagraExtend(cuvsResources_t res, +cuvsCagraExtendParams_t params, +DLManagedTensor* additional_dataset, +cuvsCagraIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` +3. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` +4. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsCagraExtendParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraextendparams) | cuvsCagraExtendParams_t used to extend CAGRA index | +| `additional_dataset` | in | `DLManagedTensor*` | DLManagedTensor* additional dataset | +| `index` | in,out | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t CAGRA index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraSearchAlgo + +Enum to denote algorithm used to search CAGRA Index + +```c +enum cuvsCagraSearchAlgo { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `SINGLE_CTA` | `0` | +| `MULTI_CTA` | `1` | +| `MULTI_KERNEL` | `2` | +| `AUTO` | `100` | + + +### cuvsCagraHashMode + +Enum to denote Hash Mode used while searching CAGRA index + +```c +enum cuvsCagraHashMode { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `HASH` | `0` | +| `SMALL` | `1` | +| `AUTO_HASH` | `100` | + + +### cuvsCagraSearchParams + +Supplemental parameters to search CAGRA index + +```c +struct cuvsCagraSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `max_queries` | `size_t` | Maximum number of queries to search at the same time (batch size). Auto select when 0. | +| `itopk_size` | `size_t` | Number of intermediate search results retained during the search. This is the main knob to adjust trade off between accuracy and search speed. Higher values improve the search accuracy. | +| `max_iterations` | `size_t` | Upper limit of search iterations. Auto select when 0. | +| `algo` | [`enum cuvsCagraSearchAlgo`](/api-reference/c-api-neighbors-cagra#cuvscagrasearchalgo) | Which search implementation to use. | +| `team_size` | `size_t` | Number of threads used to calculate a single distance. 4, 8, 16, or 32. | +| `search_width` | `size_t` | Number of graph nodes to select as the starting point for the search in each iteration. aka search width? | +| `min_iterations` | `size_t` | Lower limit of search iterations. | +| `thread_block_size` | `size_t` | Thread block size. 0, 64, 128, 256, 512, 1024. Auto selection when 0. | +| `hashmap_mode` | [`enum cuvsCagraHashMode`](/api-reference/c-api-neighbors-cagra#cuvscagrahashmode) | Hashmap type. Auto selection when AUTO. | +| `hashmap_min_bitlen` | `size_t` | Lower limit of hashmap bit length. More than 8. | +| `hashmap_max_fill_rate` | `float` | Upper limit of hashmap fill rate. More than 0.1, less than 0.9. | +| `num_random_samplings` | `uint32_t` | Number of iterations of initial random seed node selection. 1 or more. | +| `rand_xor_mask` | `uint64_t` | Bit mask used for initial random seed node selection. | +| `persistent` | `bool` | Whether to use the persistent version of the kernel (only SINGLE_CTA is supported a.t.m.) | +| `persistent_lifetime` | `float` | Persistent kernel: time in seconds before the kernel stops if no requests received. | +| `persistent_device_usage` | `float` | Set the fraction of maximum grid size used by persistent kernel. Value 1.0 means the kernel grid size is maximum possible for the selected device. The value must be greater than 0.0 and not greater than 1.0. One may need to run other kernels alongside this persistent kernel. This parameter can be used to reduce the grid size of the persistent kernel to leave a few SMs idle. Note: running any other work on GPU alongside with the persistent kernel makes the setup fragile.
- Running another kernel in another thread usually works, but no progress guaranteed
- Any CUDA allocations block the context (this issue may be obscured by using pools)
- Memory copies to not-pinned host memory may block the context Even when we know there are no other kernels working at the same time, setting kDeviceUsage to 1.0 surprisingly sometimes hurts performance. Proceed with care. If you suspect this is an issue, you can reduce this number to ~0.9 without a significant impact on the throughput. | + + +### cuvsCagraSearchParamsCreate + +Allocate CAGRA search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsCagraSearchParamsCreate(cuvsCagraSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraSearchParams_t*`](/api-reference/c-api-neighbors-cagra#cuvscagrasearchparams) | cuvsCagraSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraSearchParamsDestroy + +De-allocate CAGRA search params + +```c +CUVS_EXPORT cuvsError_t cuvsCagraSearchParamsDestroy(cuvsCagraSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsCagraSearchParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagrasearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraIndex + +Struct to hold address of cuvs::neighbors::cagra::index and its active trained dtype + +```c +typedef struct { ... } cuvsCagraIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsCagraIndexCreate + +Allocate CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexCreate(cuvsCagraIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t*`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexDestroy + +De-allocate CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexDestroy(cuvsCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexGetDims + +Get dimension of the CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexGetDims(cuvsCagraIndex_t index, int64_t* dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `dim` | out | `int64_t*` | return dimension of the index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexGetSize + +Get size of the CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexGetSize(cuvsCagraIndex_t index, int64_t* size); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `size` | out | `int64_t*` | return number of vectors in the index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexGetGraphDegree + +Get graph degree of the CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexGetGraphDegree(cuvsCagraIndex_t index, int64_t* graph_degree); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `graph_degree` | out | `int64_t*` | return graph degree | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexGetDataset + +Returns a view of the CAGRA dataset + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexGetDataset(cuvsCagraIndex_t index, DLManagedTensor* dataset); +``` + +This function returns a non-owning view of the CAGRA dataset. The output will be referencing device memory that is directly used in CAGRA, without copying the dataset at all. This means that the output is only valid as long as the CAGRA index is alive, and once cuvsCagraIndexDestroy is called on the cagra index - the returned dataset view will be invalid. + +Note that the DLManagedTensor dataset returned will have an associated 'deleter' function that must be called when the dataset is no longer needed. This will free up host memory that stores the shape of the dataset view. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `dataset` | out | `DLManagedTensor*` | the dataset used in cagra | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexGetGraph + +Returns a view of the CAGRA graph + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexGetGraph(cuvsCagraIndex_t index, DLManagedTensor* graph); +``` + +This function returns a non-owning view of the CAGRA graph. The output will be referencing device memory that is directly used in CAGRA, without copying the graph at all. This means that the output is only valid as long as the CAGRA index is alive, and once cuvsCagraIndexDestroy is called on the cagra index - the returned graph view will be invalid. + +Note that the DLManagedTensor graph returned will have an associated 'deleter' function that must be called when the graph is no longer needed. This will free up host memory that stores the metadata for the graph view. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `graph` | out | `DLManagedTensor*` | the output knn graph. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraBuild + +Build a CAGRA index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsCagraBuild(cuvsResources_t res, +cuvsCagraIndexParams_t params, +DLManagedTensor* dataset, +cuvsCagraIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` +3. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` +4. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | cuvsCagraIndexParams_t used to build CAGRA index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | inout | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t Newly built CAGRA index. This index needs to be already created with cuvsCagraIndexCreate. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsCagraSearch + +Search a CAGRA index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsCagraSearch(cuvsResources_t res, +cuvsCagraSearchParams_t params, +cuvsCagraIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances, +cuvsFilter filter); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`. It is also important to note that the CAGRA Index must have been built with the same type of `queries`, such that `index.dtype.code == queries.dl_tensor.dtype.code` Types for input are: + +1. `queries`: a. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` b. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` c. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` d. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` +2. `neighbors`: `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 32` or `kDLDataType.code == kDLInt` and `kDLDataType.bits = 64` +3. `distances`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsCagraSearchParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagrasearchparams) | cuvsCagraSearchParams_t used to search CAGRA index | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex which has been returned by `cuvsCagraBuild` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | +| `filter` | in | [`cuvsFilter`](/api-reference/c-api-neighbors-common#cuvsfilter) | cuvsFilter input filter that can be used to filter queries and neighbors based on the given bitset. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## CAGRA C-API serialize functions + + +### cuvsCagraSerialize + +Save the index to file. + +```c +CUVS_EXPORT cuvsError_t cuvsCagraSerialize(cuvsResources_t res, +const char* filename, +cuvsCagraIndex_t index, +bool include_dataset); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file name for saving the index | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraSerializeToHnswlib + +Save the CAGRA index to file in hnswlib format. + +```c +CUVS_EXPORT cuvsError_t cuvsCagraSerializeToHnswlib(cuvsResources_t res, +const char* filename, +cuvsCagraIndex_t index); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file name for saving the index | +| `index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | CAGRA index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraDeserialize + +Load index from file. + +```c +CUVS_EXPORT cuvsError_t cuvsCagraDeserialize(cuvsResources_t res, const char* filename, cuvsCagraIndex_t index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the name of the file that stores the index | +| `index` | inout | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t CAGRA index loaded from disk. This index needs to be already created with cuvsCagraIndexCreate. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsCagraIndexFromArgs + +Load index from a dataset and graph + +```c +CUVS_EXPORT cuvsError_t cuvsCagraIndexFromArgs(cuvsResources_t res, +cuvsDistanceType metric, +DLManagedTensor* graph, +DLManagedTensor* dataset, +cuvsCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | cuvsDistanceType to use in the index | +| `graph` | in | `DLManagedTensor*` | the knn graph to use, shape (size, graph_degree) | +| `dataset` | in | `DLManagedTensor*` | the dataset to use, shape (size, dim) | +| `index` | inout | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t CAGRA index populated with the graph and dataset. This index needs to be already created with cuvsCagraIndexCreate. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## CAGRA C-API merge functions + + +### cuvsCagraMerge + +Merge multiple CAGRA indices into a single CAGRA index. + +```c +CUVS_EXPORT cuvsError_t cuvsCagraMerge(cuvsResources_t res, +cuvsCagraIndexParams_t params, +cuvsCagraIndex_t* indices, +size_t num_indices, +cuvsFilter filter, +cuvsCagraIndex_t output_index); +``` + +All input indices must have been built with the same data type (`index.dtype`) and have the same dimensionality (`index.dims`). The merged index uses the output parameters specified in `cuvsCagraIndexParams`. + +Input indices must have: + +- `index.dtype.code` and `index.dtype.bits` matching across all indices. +- Supported data types for indices: a. `kDLFloat` with `bits = 32` b. `kDLFloat` with `bits = 16` c. `kDLInt` with `bits = 8` d. `kDLUInt` with `bits = 8` + +The resulting output index will have the same data type as the input indices. + +Example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | cuvsCagraIndexParams_t parameters controlling merge behavior | +| `indices` | in | [`cuvsCagraIndex_t*`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | Array of input cuvsCagraIndex_t handles to merge | +| `num_indices` | in | `size_t` | Number of input indices | +| `filter` | in | [`cuvsFilter`](/api-reference/c-api-neighbors-common#cuvsfilter) | Filter that can be used to filter out vectors from the merged index | +| `output_index` | out | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | Output handle that will store the merged index. Must be initialized using `cuvsCagraIndexCreate` before use. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-common.md b/fern/pages/c_api/c-api-neighbors-common.md new file mode 100644 index 0000000000..3cf0775d88 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-common.md @@ -0,0 +1,59 @@ +--- +slug: api-reference/c-api-neighbors-common +--- + +# Common + +_Source header: `cuvs/neighbors/common.h`_ + +## Filters APIs + + +### cuvsFilterType + +Enum to denote filter type. + +```c +enum cuvsFilterType { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `NO_FILTER` | `0` | +| `BITSET` | `1` | +| `BITMAP` | `2` | + + +### cuvsFilter + +Struct to hold address of cuvs::neighbors::prefilter and its type + +```c +typedef struct { ... } cuvsFilter; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | + +## Index Merge + + +### cuvsMergeStrategy + +Strategy for merging indices. + +```c +typedef enum { ... } cuvsMergeStrategy; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `MERGE_STRATEGY_PHYSICAL` | `0` | +| `MERGE_STRATEGY_LOGICAL` | `1` | diff --git a/fern/pages/c_api/c-api-neighbors-hnsw.md b/fern/pages/c_api/c-api-neighbors-hnsw.md new file mode 100644 index 0000000000..5889cec3ec --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-hnsw.md @@ -0,0 +1,484 @@ +--- +slug: api-reference/c-api-neighbors-hnsw +--- + +# HNSW + +_Source header: `cuvs/neighbors/hnsw.h`_ + +## C API for HNSW index params + + +### cuvsHnswHierarchy + +Hierarchy for HNSW index when converting from CAGRA index + +NOTE: When the value is `NONE`, the HNSW index is built as a base-layer-only index. + +```c +enum cuvsHnswHierarchy { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CPU` | `1` | +| `GPU` | `2` | + + +### cuvsHnswAceParams + +Parameters for ACE (Augmented Core Extraction) graph build for HNSW. + +ACE enables building indexes for datasets too large to fit in GPU memory by: + +1. Partitioning the dataset in core and augmented partitions using balanced k-means +2. Building sub-indexes for each partition independently +3. Concatenating sub-graphs into a final unified index + +```c +struct cuvsHnswAceParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `npartitions` | `size_t` | Number of partitions for ACE partitioned build. When set to 0 (default), the number of partitions is automatically derived based on available host and GPU memory to maximize partition size while ensuring the build fits in memory. Small values might improve recall but potentially degrade performance and increase memory usage. The partition size is on average 2 * (n_rows / npartitions) * dim * sizeof(T). 2 is because of the core and augmented vectors. Please account for imbalance in the partition sizes (up to 3x in our tests). If the specified number of partitions results in partitions that exceed available memory, the value will be automatically increased to fit memory constraints and a warning will be issued. | +| `build_dir` | `const char*` | Directory to store ACE build artifacts (e.g., KNN graph, optimized graph). Used when `use_disk` is true or when the graph does not fit in memory. | +| `use_disk` | `bool` | Whether to use disk-based storage for ACE build. When true, enables disk-based operations for memory-efficient graph construction. | +| `max_host_memory_gb` | `double` | Maximum host memory to use for ACE build in GiB. When set to 0 (default), uses available host memory. Useful for testing or when running alongside other memory-intensive processes. | +| `max_gpu_memory_gb` | `double` | Maximum GPU memory to use for ACE build in GiB. When set to 0 (default), uses available GPU memory. Useful for testing or when running alongside other memory-intensive processes. | + + +### cuvsHnswAceParamsCreate + +Allocate HNSW ACE params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsHnswAceParamsCreate(cuvsHnswAceParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswAceParams_t*`](/api-reference/c-api-neighbors-hnsw#cuvshnswaceparams) | cuvsHnswAceParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswAceParamsDestroy + +De-allocate HNSW ACE params + +```c +CUVS_EXPORT cuvsError_t cuvsHnswAceParamsDestroy(cuvsHnswAceParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswAceParams_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswaceparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswIndexParamsCreate + +Allocate HNSW Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsHnswIndexParamsCreate(cuvsHnswIndexParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | `cuvsHnswIndexParams_t*` | cuvsHnswIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswIndexParamsDestroy + +De-allocate HNSW Index params + +```c +CUVS_EXPORT cuvsError_t cuvsHnswIndexParamsDestroy(cuvsHnswIndexParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | `cuvsHnswIndexParams_t` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for hnswlib wrapper index + + +### cuvsHnswIndex + +Struct to hold address of cuvs::neighbors::Hnsw::index and its active trained dtype + +```c +typedef struct { ... } cuvsHnswIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsHnswIndexCreate + +Allocate HNSW index + +```c +CUVS_EXPORT cuvsError_t cuvsHnswIndexCreate(cuvsHnswIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsHnswIndex_t*`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswIndexDestroy + +De-allocate HNSW index + +```c +CUVS_EXPORT cuvsError_t cuvsHnswIndexDestroy(cuvsHnswIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Parameters for extending HNSW index + + +### cuvsHnswExtendParams + +Parameters for extending HNSW index + +```c +struct cuvsHnswExtendParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `num_threads` | `int` | Number of CPU threads used to extend additional vectors | + + +### cuvsHnswExtendParamsCreate + +Allocate HNSW extend params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsHnswExtendParamsCreate(cuvsHnswExtendParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswExtendParams_t*`](/api-reference/c-api-neighbors-hnsw#cuvshnswextendparams) | cuvsHnswExtendParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswExtendParamsDestroy + +De-allocate HNSW extend params + +```c +CUVS_EXPORT cuvsError_t cuvsHnswExtendParamsDestroy(cuvsHnswExtendParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswExtendParams_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswextendparams) | cuvsHnswExtendParams_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Load CAGRA index as hnswlib index + + +### cuvsHnswFromCagra + +Convert a CAGRA Index to an HNSW index. + +```c +CUVS_EXPORT cuvsError_t cuvsHnswFromCagra(cuvsResources_t res, +cuvsHnswIndexParams_t params, +cuvsCagraIndex_t cagra_index, +cuvsHnswIndex_t hnsw_index); +``` + +NOTE: When hierarchy is: + +1. `NONE`: This method uses the filesystem to write the CAGRA index in `/tmp/<random_number>.bin` before reading it as an hnswlib index, then deleting the temporary file. The returned index is immutable and can only be searched by the hnswlib wrapper in cuVS, as the format is not compatible with the original hnswlib. +2. `CPU`: The returned index is mutable and can be extended with additional vectors. The serialized index is also compatible with the original hnswlib library. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | `cuvsHnswIndexParams_t` | cuvsHnswIndexParams_t used to load Hnsw index | +| `cagra_index` | in | [`cuvsCagraIndex_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindex) | cuvsCagraIndex_t to convert to HNSW index | +| `hnsw_index` | out | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to return the HNSW index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Build HNSW index using ACE algorithm + + +### cuvsHnswBuild + +Build an HNSW index using ACE (Augmented Core Extraction) algorithm. + +```c +CUVS_EXPORT cuvsError_t cuvsHnswBuild(cuvsResources_t res, +cuvsHnswIndexParams_t params, +DLManagedTensor* dataset, +cuvsHnswIndex_t index); +``` + +ACE enables building HNSW indexes for datasets too large to fit in GPU memory by: + +1. Partitioning the dataset using balanced k-means into core and augmented partitions +2. Building sub-indexes for each partition independently +3. Concatenating sub-graphs into a final unified index + +NOTE: This function requires CUDA to be available at runtime. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | `cuvsHnswIndexParams_t` | cuvsHnswIndexParams_t with ACE parameters configured | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* host dataset to build index from | +| `index` | out | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to return the built HNSW index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Extend HNSW index with additional vectors + + +### cuvsHnswExtend + +Add new vectors to an HNSW index + +```c +CUVS_EXPORT cuvsError_t cuvsHnswExtend(cuvsResources_t res, +cuvsHnswExtendParams_t params, +DLManagedTensor* additional_dataset, +cuvsHnswIndex_t index); +``` + +NOTE: The HNSW index can only be extended when the hierarchy is `CPU` when converting from a CAGRA index. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsHnswExtendParams_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswextendparams) | cuvsHnswExtendParams_t used to extend Hnsw index | +| `additional_dataset` | in | `DLManagedTensor*` | DLManagedTensor* additional dataset to extend the index | +| `index` | inout | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to extend | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for hnswlib wrapper search params + + +### cuvsHnswSearchParams + +C API for hnswlib wrapper search params + +```c +struct cuvsHnswSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `ef` | `int32_t` | | +| `num_threads` | `int32_t` | | + + +### cuvsHnswSearchParamsCreate + +Allocate HNSW search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsHnswSearchParamsCreate(cuvsHnswSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswSearchParams_t*`](/api-reference/c-api-neighbors-hnsw#cuvshnswsearchparams) | cuvsHnswSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswSearchParamsDestroy + +De-allocate HNSW search params + +```c +CUVS_EXPORT cuvsError_t cuvsHnswSearchParamsDestroy(cuvsHnswSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsHnswSearchParams_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswsearchparams) | cuvsHnswSearchParams_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## C API for CUDA ANN Graph-based nearest neighbor search + + +### cuvsHnswSearch + +Search a HNSW index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsHnswSearch(cuvsResources_t res, +cuvsHnswSearchParams_t params, +cuvsHnswIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances); +``` + +`DLDeviceType` equal to `kDLCPU`, `kDLCUDAHost`, or `kDLCUDAManaged`. It is also important to note that the HNSW Index must have been built with the same type of `queries`, such that `index.dtype.code == queries.dl_tensor.dtype.code` Supported types for input are: + +1. `queries`: a. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` b. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` c. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` +2. `neighbors`: `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 64` +3. `distances`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` NOTE: When hierarchy is `NONE`, the HNSW index can only be searched by the hnswlib wrapper in cuVS, as the format is not compatible with the original hnswlib. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsHnswSearchParams_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswsearchparams) | cuvsHnswSearchParams_t used to search Hnsw index | +| `index` | in | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex which has been returned by `cuvsHnswFromCagra` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## HNSW C-API serialize functions + + +### cuvsHnswSerialize + +Serialize a CAGRA index to a file as an hnswlib index + +```c +CUVS_EXPORT cuvsError_t cuvsHnswSerialize(cuvsResources_t res, const char* filename, cuvsHnswIndex_t index); +``` + +NOTE: When hierarchy is `NONE`, the saved hnswlib index is immutable and can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. However, when hierarchy is `CPU`, the saved hnswlib index is compatible with the original hnswlib library. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the name of the file to save the index | +| `index` | in | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | cuvsHnswIndex_t to serialize | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsHnswDeserialize + +Load hnswlib index from file which was serialized from a HNSW index. + +```c +CUVS_EXPORT cuvsError_t cuvsHnswDeserialize(cuvsResources_t res, +cuvsHnswIndexParams_t params, +const char* filename, +int dim, +cuvsDistanceType metric, +cuvsHnswIndex_t index); +``` + +NOTE: When hierarchy is `NONE`, the loaded hnswlib index is immutable, and only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | `cuvsHnswIndexParams_t` | cuvsHnswIndexParams_t used to load Hnsw index | +| `filename` | in | `const char*` | the name of the file that stores the index | +| `dim` | in | `int` | the dimension of the vectors in the index | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | the distance metric used to build the index | +| `index` | out | [`cuvsHnswIndex_t`](/api-reference/c-api-neighbors-hnsw#cuvshnswindex) | HNSW index loaded disk | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-ivf-flat.md b/fern/pages/c_api/c-api-neighbors-ivf-flat.md new file mode 100644 index 0000000000..cfe869fd53 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-ivf-flat.md @@ -0,0 +1,391 @@ +--- +slug: api-reference/c-api-neighbors-ivf-flat +--- + +# IVF Flat + +_Source header: `cuvs/neighbors/ivf_flat.h`_ + +## IVF-Flat index build parameters + + +### cuvsIvfFlatIndexParams + +Supplemental parameters to build IVF-Flat Index + +```c +struct cuvsIvfFlatIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance type. | +| `metric_arg` | `float` | The argument used by some distance metrics. | +| `add_data_on_build` | `bool` | Whether to add the dataset content to the index, i.e.:
- `true` means the index is filled with the dataset vectors and ready to search after calling `build`.
- `false` means `build` only trains the underlying model (e.g. quantizer or clustering), but the index is left empty; you'd need to call `extend` on the index afterwards to populate it. | +| `n_lists` | `uint32_t` | The number of inverted lists (clusters) | +| `kmeans_n_iters` | `uint32_t` | The number of iterations searching for kmeans centers (index building). | +| `kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building. | +| `adaptive_centers` | `bool` | By default (adaptive_centers = false), the cluster centers are trained in `ivf_flat::build`, and never modified in `ivf_flat::extend`. As a result, you may need to retrain the index from scratch after invoking (`ivf_flat::extend`) a few times with new data, the distribution of which is no longer representative of the original training set. The alternative behavior (adaptive_centers = true) is to update the cluster centers for new data when it is added. In this case, `index.centers()` are always exactly the centroids of the data in the corresponding clusters. The drawback of this behavior is that the centroids depend on the order of adding new data (through the classification of the added data); that is, `index.centers()` "drift" together with the changing distribution of the newly added data. | +| `conservative_memory_allocation` | `bool` | By default, the algorithm allocates more space than necessary for individual clusters (`list_data`). This allows to amortize the cost of memory allocation and reduce the number of data copies during repeated calls to `extend` (extending the database). The alternative is the conservative allocation behavior; when enabled, the algorithm always allocates the minimum amount of memory required to store the given number of records. Set this flag to `true` if you prefer to use as little GPU memory for the database as possible. | + + +### cuvsIvfFlatIndexParamsCreate + +Allocate IVF-Flat Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexParamsCreate(cuvsIvfFlatIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsIvfFlatIndexParams_t*`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindexparams) | cuvsIvfFlatIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatIndexParamsDestroy + +De-allocate IVF-Flat Index params + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexParamsDestroy(cuvsIvfFlatIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat index search parameters + + +### cuvsIvfFlatSearchParams + +Supplemental parameters to search IVF-Flat index + +```c +struct cuvsIvfFlatSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_probes` | `uint32_t` | The number of clusters to search. | + + +### cuvsIvfFlatSearchParamsCreate + +Allocate IVF-Flat search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatSearchParamsCreate(cuvsIvfFlatSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsIvfFlatSearchParams_t*`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatsearchparams) | cuvsIvfFlatSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatSearchParamsDestroy + +De-allocate IVF-Flat search params + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatSearchParamsDestroy(cuvsIvfFlatSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsIvfFlatSearchParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatsearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat index + + +### cuvsIvfFlatIndex + +Struct to hold address of cuvs::neighbors::ivf_flat::index and its active trained dtype + +```c +typedef struct { ... } cuvsIvfFlatIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsIvfFlatIndexCreate + +Allocate IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexCreate(cuvsIvfFlatIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfFlatIndex_t*`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatIndexDestroy + +De-allocate IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexDestroy(cuvsIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatIndexGetNLists + +Get the number of clusters/inverted lists in the index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexGetNLists(cuvsIvfFlatIndex_t index, int64_t* n_lists); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t Built IVF-Flat index | +| `n_lists` | out | `int64_t*` | Pointer to store the number of lists | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatIndexGetDim + +Get the dimensionality of the indexed data + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexGetDim(cuvsIvfFlatIndex_t index, int64_t* dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t Built IVF-Flat index | +| `dim` | out | `int64_t*` | Pointer to store the dimensionality | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatIndexGetCenters + +Get the cluster centers corresponding to the lists [n_lists, dim] + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatIndexGetCenters(cuvsIvfFlatIndex_t index, DLManagedTensor* centers); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t Built Ivf-Flat Index | +| `centers` | out | `DLManagedTensor*` | Preallocated array on host or device memory to store output, [n_lists, dim] | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat index build + + +### cuvsIvfFlatBuild + +Build a IVF-Flat index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatBuild(cuvsResources_t res, +cuvsIvfFlatIndexParams_t index_params, +DLManagedTensor* dataset, +cuvsIvfFlatIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` +3. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index_params` | in | [`cuvsIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindexparams) | cuvsIvfFlatIndexParams_t used to build IVF-Flat index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | cuvsIvfFlatIndex_t Newly built IVF-Flat index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat index search + + +### cuvsIvfFlatSearch + +Search a IVF-Flat index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatSearch(cuvsResources_t res, +cuvsIvfFlatSearchParams_t search_params, +cuvsIvfFlatIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances, +cuvsFilter filter); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`. It is also important to note that the IVF-Flat Index must have been built with the same type of `queries`, such that `index.dtype.code == queries.dl_tensor.dtype.code` Types for input are: + +1. `queries`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `neighbors`: `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 32` +3. `distances`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `search_params` | in | [`cuvsIvfFlatSearchParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatsearchparams) | cuvsIvfFlatSearchParams_t used to search IVF-Flat index | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | ivfFlatIndex which has been returned by `ivfFlatBuild` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | +| `filter` | in | [`cuvsFilter`](/api-reference/c-api-neighbors-common#cuvsfilter) | cuvsFilter input filter that can be used to filter queries and neighbors based on the given bitset. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat C-API serialize functions + + +### cuvsIvfFlatSerialize + +Save the index to file. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatSerialize(cuvsResources_t res, +const char* filename, +cuvsIvfFlatIndex_t index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file name for saving the index | +| `index` | in | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | IVF-Flat index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfFlatDeserialize + +Load index from file. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatDeserialize(cuvsResources_t res, +const char* filename, +cuvsIvfFlatIndex_t index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the name of the file that stores the index | +| `index` | out | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | IVF-Flat index loaded disk | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-Flat index extend + + +### cuvsIvfFlatExtend + +Extend the index with the new data. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfFlatExtend(cuvsResources_t res, +DLManagedTensor* new_vectors, +DLManagedTensor* new_indices, +cuvsIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `new_vectors` | in | `DLManagedTensor*` | DLManagedTensor* the new vectors to add to the index | +| `new_indices` | in | `DLManagedTensor*` | DLManagedTensor* vector of new indices for the new vectors | +| `index` | inout | [`cuvsIvfFlatIndex_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindex) | IVF-Flat index to be extended | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-ivf-pq.md b/fern/pages/c_api/c-api-neighbors-ivf-pq.md new file mode 100644 index 0000000000..b32a8eef7f --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-ivf-pq.md @@ -0,0 +1,748 @@ +--- +slug: api-reference/c-api-neighbors-ivf-pq +--- + +# IVF PQ + +_Source header: `cuvs/neighbors/ivf_pq.h`_ + +## IVF-PQ index build parameters + + +### cuvsIvfPqCodebookGen + +A type for specifying how PQ codebooks are created + +```c +enum cuvsIvfPqCodebookGen { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_IVF_PQ_CODEBOOK_GEN_PER_SUBSPACE` | `0` | +| `CUVS_IVF_PQ_CODEBOOK_GEN_PER_CLUSTER` | `1` | + + +### cuvsIvfPqListLayout + +A type for specifying the memory layout of IVF-PQ list data + +```c +enum cuvsIvfPqListLayout { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_IVF_PQ_LIST_LAYOUT_FLAT` | `0` | +| `CUVS_IVF_PQ_LIST_LAYOUT_INTERLEAVED` | `1` | + + +### cuvsIvfPqIndexParams + +Supplemental parameters to build IVF-PQ Index + +```c +struct cuvsIvfPqIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance type. | +| `metric_arg` | `float` | The argument used by some distance metrics. | +| `add_data_on_build` | `bool` | Whether to add the dataset content to the index, i.e.:
- `true` means the index is filled with the dataset vectors and ready to search after calling `build`.
- `false` means `build` only trains the underlying model (e.g. quantizer or clustering), but the index is left empty; you'd need to call `extend` on the index afterwards to populate it. | +| `n_lists` | `uint32_t` | The number of inverted lists (clusters) Hint: the number of vectors per cluster (`n_rows/n_lists`) should be approximately 1,000 to 10,000. | +| `kmeans_n_iters` | `uint32_t` | The number of iterations searching for kmeans centers (index building). | +| `kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building. | +| `pq_bits` | `uint32_t` | The bit length of the vector element after compression by PQ. Possible values: [4, 5, 6, 7, 8]. Hint: the smaller the 'pq_bits', the smaller the index size and the better the search performance, but the lower the recall. | +| `pq_dim` | `uint32_t` | The dimensionality of the vector after compression by PQ. When zero, an optimal value is selected using a heuristic. NB: `pq_dim * pq_bits` must be a multiple of 8. Hint: a smaller 'pq_dim' results in a smaller index size and better search performance, but lower recall. If 'pq_bits' is 8, 'pq_dim' can be set to any number, but multiple of 8 are desirable for good performance. If 'pq_bits' is not 8, 'pq_dim' should be a multiple of 8. For good performance, it is desirable that 'pq_dim' is a multiple of 32. Ideally, 'pq_dim' should be also a divisor of the dataset dim. | +| `codebook_kind` | [`enum cuvsIvfPqCodebookGen`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqcodebookgen) | How PQ codebooks are created. | +| `force_random_rotation` | `bool` | Apply a random rotation matrix on the input data and queries even if `dim % pq_dim == 0`. Note: if `dim` is not multiple of `pq_dim`, a random rotation is always applied to the input data and queries to transform the working space from `dim` to `rot_dim`, which may be slightly larger than the original space and and is a multiple of `pq_dim` (`rot_dim % pq_dim == 0`). However, this transform is not necessary when `dim` is multiple of `pq_dim` (`dim == rot_dim`, hence no need in adding "extra" data columns / features). By default, if `dim == rot_dim`, the rotation transform is initialized with the identity matrix. When `force_random_rotation == true`, a random orthogonal transform matrix is generated regardless of the values of `dim` and `pq_dim`. | +| `conservative_memory_allocation` | `bool` | By default, the algorithm allocates more space than necessary for individual clusters (`list_data`). This allows to amortize the cost of memory allocation and reduce the number of data copies during repeated calls to `extend` (extending the database). The alternative is the conservative allocation behavior; when enabled, the algorithm always allocates the minimum amount of memory required to store the given number of records. Set this flag to `true` if you prefer to use as little GPU memory for the database as possible. | +| `max_train_points_per_pq_code` | `uint32_t` | The max number of data points to use per PQ code during PQ codebook training. Using more data points per PQ code may increase the quality of PQ codebook but may also increase the build time. The parameter is applied to both PQ codebook generation methods, i.e., PER_SUBSPACE and PER_CLUSTER. In both cases, we will use `pq_book_size * max_train_points_per_pq_code` training points to train each codebook. | +| `codes_layout` | [`enum cuvsIvfPqListLayout`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqlistlayout) | Memory layout of the IVF-PQ list data.
- CUVS_IVF_PQ_LIST_LAYOUT_FLAT: Codes are stored contiguously, one vector's codes after another.
- CUVS_IVF_PQ_LIST_LAYOUT_INTERLEAVED: Codes are interleaved for optimized search performance. This is the default and recommended for search workloads. | + + +### cuvsIvfPqIndexParamsCreate + +Allocate IVF-PQ Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexParamsCreate(cuvsIvfPqIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsIvfPqIndexParams_t*`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | cuvsIvfPqIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexParamsDestroy + +De-allocate IVF-PQ Index params + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexParamsDestroy(cuvsIvfPqIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index search parameters + + +### cuvsIvfPqSearchParams + +Supplemental parameters to search IVF-PQ index + +```c +struct cuvsIvfPqSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_probes` | `uint32_t` | The number of clusters to search. | +| `lut_dtype` | `cudaDataType_t` | Data type of look up table to be created dynamically at search time. Possible values: [CUDA_R_32F, CUDA_R_16F, CUDA_R_8U] The use of low-precision types reduces the amount of shared memory required at search time, so fast shared memory kernels can be used even for datasets with large dimansionality. Note that the recall is slightly degraded when low-precision type is selected. | +| `internal_distance_dtype` | `cudaDataType_t` | Storage data type for distance/similarity computed at search time. Possible values: [CUDA_R_16F, CUDA_R_32F] If the performance limiter at search time is device memory access, selecting FP16 will improve performance slightly. | +| `coarse_search_dtype` | `cudaDataType_t` | The data type to use as the GEMM element type when searching the clusters to probe. Possible values: [CUDA_R_8I, CUDA_R_16F, CUDA_R_32F].
- Legacy default: CUDA_R_32F (float)
- Recommended for performance: CUDA_R_16F (half)
- Experimental/low-precision: CUDA_R_8I (int8_t) (WARNING: int8_t variant degrades recall unless data is normalized and low-dimensional) | +| `max_internal_batch_size` | `uint32_t` | Set the internal batch size to improve GPU utilization at the cost of larger memory footprint. | +| `preferred_shmem_carveout` | `double` | Preferred fraction of SM's unified memory / L1 cache to be used as shared memory. Possible values: [0.0 - 1.0] as a fraction of the `sharedMemPerMultiprocessor`. One wants to increase the carveout to make sure a good GPU occupancy for the main search kernel, but not to keep it too high to leave some memory to be used as L1 cache. Note, this value is interpreted only as a hint. Moreover, a GPU usually allows only a fixed set of cache configurations, so the provided value is rounded up to the nearest configuration. Refer to the NVIDIA tuning guide for the target GPU architecture. Note, this is a low-level tuning parameter that can have drastic negative effects on the search performance if tweaked incorrectly. | + + +### cuvsIvfPqSearchParamsCreate + +Allocate IVF-PQ search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqSearchParamsCreate(cuvsIvfPqSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsIvfPqSearchParams_t*`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqsearchparams) | cuvsIvfPqSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqSearchParamsDestroy + +De-allocate IVF-PQ search params + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqSearchParamsDestroy(cuvsIvfPqSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsIvfPqSearchParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqsearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index + + +### cuvsIvfPqIndex + +Struct to hold address of cuvs::neighbors::ivf_pq::index and its active trained dtype + +```c +typedef struct { ... } cuvsIvfPqIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsIvfPqIndexCreate + +Allocate IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexCreate(cuvsIvfPqIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t*`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexDestroy + +De-allocate IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexDestroy(cuvsIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetNLists + +Get the number of clusters/inverted lists + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetNLists(cuvsIvfPqIndex_t index, int64_t* n_lists); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `n_lists` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetDim + +Get the dimensionality + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetDim(cuvsIvfPqIndex_t index, int64_t* dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `dim` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetSize + +Get the size of the index + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetSize(cuvsIvfPqIndex_t index, int64_t* size); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `size` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetPqDim + +Get the dimensionality of an encoded vector after compression by PQ. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetPqDim(cuvsIvfPqIndex_t index, int64_t* pq_dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `pq_dim` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetPqBits + +Get the bit length of an encoded vector element after compression by PQ. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetPqBits(cuvsIvfPqIndex_t index, int64_t* pq_bits); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `pq_bits` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetPqLen + +Get the Dimensionality of a subspace, i.e. the number of vector + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetPqLen(cuvsIvfPqIndex_t index, int64_t* pq_len); +``` + +components mapped to a subspace + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | | +| `pq_len` | | `int64_t*` | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetCenters + +Get the cluster centers corresponding to the lists in the original space + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetCenters(cuvsIvfPqIndex_t index, DLManagedTensor* centers); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `centers` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetCentersPadded + +Get the padded cluster centers [n_lists, dim_ext] + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetCentersPadded(cuvsIvfPqIndex_t index, DLManagedTensor* centers); +``` + +where dim_ext = round_up(dim + 1, 8) + +This returns the full padded centers as a contiguous array, suitable for use with cuvsIvfPqBuildPrecomputed. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `centers` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetPqCenters + +Get the PQ cluster centers + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetPqCenters(cuvsIvfPqIndex_t index, DLManagedTensor* pq_centers); +``` + +- CUVS_IVF_PQ_CODEBOOK_GEN_PER_SUBSPACE: [pq_dim , pq_len, pq_book_size] +- CUVS_IVF_PQ_CODEBOOK_GEN_PER_CLUSTER: [n_lists, pq_len, pq_book_size] + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `pq_centers` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetCentersRot + +Get the rotated cluster centers [n_lists, rot_dim] + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetCentersRot(cuvsIvfPqIndex_t index, DLManagedTensor* centers_rot); +``` + +where rot_dim = pq_len * pq_dim + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `centers_rot` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetRotationMatrix + +Get the rotation matrix [rot_dim, dim] + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetRotationMatrix(cuvsIvfPqIndex_t index, +DLManagedTensor* rotation_matrix); +``` + +Transform matrix (original space -> rotated padded space) + +data + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `rotation_matrix` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetListSizes + +Get the sizes of each list + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetListSizes(cuvsIvfPqIndex_t index, DLManagedTensor* list_sizes); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `list_sizes` | out | `DLManagedTensor*` | Output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexUnpackContiguousListData + +Unpack `n_rows` consecutive PQ encoded vectors of a single list (cluster) in the + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexUnpackContiguousListData(cuvsResources_t res, +cuvsIvfPqIndex_t index, +DLManagedTensor* out_codes, +uint32_t label, +uint32_t offset); +``` + +compressed index starting at given `offset`, not expanded to one code per byte. Each code in the output buffer occupies ceildiv(index.pq_dim() * index.pq_bits(), 8) bytes. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `out_codes` | out | `DLManagedTensor*` | the destination buffer [n_rows, ceildiv(index.pq_dim() * index.pq_bits(), 8)]. The length `n_rows` defines how many records to unpack, offset + n_rows must be smaller than or equal to the list size. This DLManagedTensor must already point to allocated device memory | +| `label` | in | `uint32_t` | The id of the list (cluster) to decode. | +| `offset` | in | `uint32_t` | How many records in the list to skip. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqIndexGetListIndices + +Get the indices of each vector in a ivf-pq list + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqIndexGetListIndices(cuvsIvfPqIndex_t index, +uint32_t label, +DLManagedTensor* out_labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Built Ivf-Pq index | +| `label` | in | `uint32_t` | The id of the list (cluster) to decode. | +| `out_labels` | out | `DLManagedTensor*` | output tensor that will be populated with a non-owning view of the data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index build + + +### cuvsIvfPqBuild + +Build a IVF-PQ index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqBuild(cuvsResources_t res, +cuvsIvfPqIndexParams_t params, +DLManagedTensor* dataset, +cuvsIvfPqIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` +3. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` +4. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | cuvsIvfPqIndexParams_t used to build IVF-PQ index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Newly built IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqBuildPrecomputed + +Build a view-type IVF-PQ index from device memory precomputed centroids and codebook. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqBuildPrecomputed(cuvsResources_t res, +cuvsIvfPqIndexParams_t params, +uint32_t dim, +DLManagedTensor* pq_centers, +DLManagedTensor* centers, +DLManagedTensor* centers_rot, +DLManagedTensor* rotation_matrix, +cuvsIvfPqIndex_t index); +``` + +This function creates a non-owning index that stores a reference to the provided device data. All parameters must be provided with correct extents. The caller is responsible for ensuring the lifetime of the input data exceeds the lifetime of the returned index. + +The index_params must be consistent with the provided matrices. Specifically: + +- index_params.codebook_kind determines the expected shape of pq_centers +- index_params.metric will be stored in the index +- index_params.conservative_memory_allocation will be stored in the index The function will verify consistency between index_params, dim, and the matrix extents. + +matrices) dim] + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | cuvsIvfPqIndexParams_t used to configure the index (must be consistent with | +| `dim` | in | `uint32_t` | dimensionality of the input data | +| `pq_centers` | in | `DLManagedTensor*` | PQ codebook on device memory with required shape:
- codebook_kind CUVS_IVF_PQ_CODEBOOK_GEN_PER_SUBSPACE: [pq_dim, pq_len, pq_book_size]
- codebook_kind CUVS_IVF_PQ_CODEBOOK_GEN_PER_CLUSTER: [n_lists, pq_len, pq_book_size] | +| `centers` | in | `DLManagedTensor*` | Cluster centers in the original space [n_lists, dim_ext] where dim_ext = round_up(dim + 1, 8) | +| `centers_rot` | in | `DLManagedTensor*` | Rotated cluster centers [n_lists, rot_dim] where rot_dim = pq_len * pq_dim | +| `rotation_matrix` | in | `DLManagedTensor*` | Transform matrix (original space -> rotated padded space) [rot_dim, | +| `index` | out | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex_t Newly built view-type IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index search + + +### cuvsIvfPqSearch + +Search a IVF-PQ index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqSearch(cuvsResources_t res, +cuvsIvfPqSearchParams_t search_params, +cuvsIvfPqIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`. It is also important to note that the IVF-PQ Index must have been built with the same type of `queries`, such that `index.dtype.code == queries.dl_tensor.dtype.code` Types for input are: + +1. `queries`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` or `kDLDataType.bits = 16` +2. `neighbors`: `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 32` +3. `distances`: `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `search_params` | in | [`cuvsIvfPqSearchParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqsearchparams) | cuvsIvfPqSearchParams_t used to search IVF-PQ index | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | cuvsIvfPqIndex which has been returned by `cuvsIvfPqBuild` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ C-API serialize functions + + +### cuvsIvfPqSerialize + +Save the index to file. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqSerialize(cuvsResources_t res, const char* filename, cuvsIvfPqIndex_t index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file name for saving the index | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsIvfPqDeserialize + +Load index from file. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqDeserialize(cuvsResources_t res, const char* filename, cuvsIvfPqIndex_t index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the name of the file that stores the index | +| `index` | out | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | IVF-PQ index loaded disk | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index extend + + +### cuvsIvfPqExtend + +Extend the index with the new data. + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqExtend(cuvsResources_t res, +DLManagedTensor* new_vectors, +DLManagedTensor* new_indices, +cuvsIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `new_vectors` | in | `DLManagedTensor*` | DLManagedTensor* the new vectors to add to the index | +| `new_indices` | in | `DLManagedTensor*` | DLManagedTensor* vector of new indices for the new vectors | +| `index` | inout | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | IVF-PQ index to be extended | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## IVF-PQ index transform + + +### cuvsIvfPqTransform + +Transform the input data by applying pq-encoding + +```c +CUVS_EXPORT cuvsError_t cuvsIvfPqTransform(cuvsResources_t res, +cuvsIvfPqIndex_t index, +DLManagedTensor* input_dataset, +DLManagedTensor* output_labels, +DLManagedTensor* output_dataset); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in | [`cuvsIvfPqIndex_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindex) | IVF-PQ index | +| `input_dataset` | in | `DLManagedTensor*` | DLManagedTensor* vectors to transform | +| `output_labels` | out | `DLManagedTensor*` | DLManagedTensor* Vector of cluster labels for each vector in the input | +| `output_dataset` | out | `DLManagedTensor*` | DLManagedTensor* input vectors after pq-encoding | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-mg-cagra.md b/fern/pages/c_api/c-api-neighbors-mg-cagra.md new file mode 100644 index 0000000000..36b26b9d87 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-mg-cagra.md @@ -0,0 +1,343 @@ +--- +slug: api-reference/c-api-neighbors-mg-cagra +--- + +# Multi-GPU Cagra + +_Source header: `cuvs/neighbors/mg_cagra.h`_ + +## Multi-GPU CAGRA index build parameters + + +### cuvsMultiGpuCagraIndexParams + +Multi-GPU parameters to build CAGRA Index + +This structure extends the base CAGRA index parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuCagraIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | Base CAGRA index parameters | +| `mode` | [`cuvsMultiGpuDistributionMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpudistributionmode) | Distribution mode for multi-GPU setup | + + +### cuvsMultiGpuCagraIndexParamsCreate + +Allocate Multi-GPU CAGRA Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraIndexParamsCreate(cuvsMultiGpuCagraIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuCagraIndexParams_t*`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindexparams) | cuvsMultiGpuCagraIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuCagraIndexParamsDestroy + +De-allocate Multi-GPU CAGRA Index params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraIndexParamsDestroy(cuvsMultiGpuCagraIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuCagraIndexParams_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index search parameters + + +### cuvsMultiGpuCagraSearchParams + +Multi-GPU parameters to search CAGRA index + +This structure extends the base CAGRA search parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuCagraSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsCagraSearchParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagrasearchparams) | Base CAGRA search parameters | +| `search_mode` | [`cuvsMultiGpuReplicatedSearchMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpureplicatedsearchmode) | Replicated search mode | +| `merge_mode` | [`cuvsMultiGpuShardedMergeMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpushardedmergemode) | Sharded merge mode | +| `n_rows_per_batch` | `int64_t` | Number of rows per batch | + + +### cuvsMultiGpuCagraSearchParamsCreate + +Allocate Multi-GPU CAGRA search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraSearchParamsCreate(cuvsMultiGpuCagraSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuCagraSearchParams_t*`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagrasearchparams) | cuvsMultiGpuCagraSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuCagraSearchParamsDestroy + +De-allocate Multi-GPU CAGRA search params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraSearchParamsDestroy(cuvsMultiGpuCagraSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuCagraSearchParams_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagrasearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index + + +### cuvsMultiGpuCagraIndex + +Struct to hold address of cuvs::neighbors::mg_index<cagra::index> and its active trained + +dtype + +```c +typedef struct { ... } cuvsMultiGpuCagraIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsMultiGpuCagraIndexCreate + +Allocate Multi-GPU CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraIndexCreate(cuvsMultiGpuCagraIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuCagraIndex_t*`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | cuvsMultiGpuCagraIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuCagraIndexDestroy + +De-allocate Multi-GPU CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraIndexDestroy(cuvsMultiGpuCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | cuvsMultiGpuCagraIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index build + + +### cuvsMultiGpuCagraBuild + +Build a Multi-GPU CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraBuild(cuvsResources_t res, +cuvsMultiGpuCagraIndexParams_t params, +DLManagedTensor* dataset_tensor, +cuvsMultiGpuCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuCagraIndexParams_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindexparams) | Multi-GPU CAGRA index parameters | +| `dataset_tensor` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index search + + +### cuvsMultiGpuCagraSearch + +Search a Multi-GPU CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraSearch(cuvsResources_t res, +cuvsMultiGpuCagraSearchParams_t params, +cuvsMultiGpuCagraIndex_t index, +DLManagedTensor* queries_tensor, +DLManagedTensor* neighbors_tensor, +DLManagedTensor* distances_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuCagraSearchParams_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagrasearchparams) | Multi-GPU CAGRA search parameters | +| `index` | in | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index | +| `queries_tensor` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset | +| `neighbors_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output neighbors | +| `distances_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output distances | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index extend + + +### cuvsMultiGpuCagraExtend + +Extend a Multi-GPU CAGRA index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraExtend(cuvsResources_t res, +cuvsMultiGpuCagraIndex_t index, +DLManagedTensor* new_vectors_tensor, +DLManagedTensor* new_indices_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in,out | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index to extend | +| `new_vectors_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new vectors to add | +| `new_indices_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new indices (optional, can be NULL) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index serialize + + +### cuvsMultiGpuCagraSerialize + +Serialize a Multi-GPU CAGRA index to file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraSerialize(cuvsResources_t res, +cuvsMultiGpuCagraIndex_t index, +const char* filename); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index to serialize | +| `filename` | in | `const char*` | Path to the output file | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index deserialize + + +### cuvsMultiGpuCagraDeserialize + +Deserialize a Multi-GPU CAGRA index from file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraDeserialize(cuvsResources_t res, +const char* filename, +cuvsMultiGpuCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the input file | +| `index` | out | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU CAGRA index distribute + + +### cuvsMultiGpuCagraDistribute + +Distribute a local CAGRA index to create a Multi-GPU index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuCagraDistribute(cuvsResources_t res, +const char* filename, +cuvsMultiGpuCagraIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the local index file | +| `index` | out | [`cuvsMultiGpuCagraIndex_t`](/api-reference/c-api-neighbors-mg-cagra#cuvsmultigpucagraindex) | Multi-GPU CAGRA index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-mg-common.md b/fern/pages/c_api/c-api-neighbors-mg-common.md new file mode 100644 index 0000000000..951c0967ce --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-mg-common.md @@ -0,0 +1,50 @@ +--- +slug: api-reference/c-api-neighbors-mg-common +--- + +# Multi-GPU Common + +_Source header: `cuvs/neighbors/mg_common.h`_ + +## Multi-GPU common types and enums + + +### cuvsMultiGpuDistributionMode + +Distribution mode for multi-GPU indexes + +```c +typedef enum { ... } cuvsMultiGpuDistributionMode; +``` + + +### cuvsMultiGpuReplicatedSearchMode + +Search mode when using a replicated index + +```c +typedef enum { ... } cuvsMultiGpuReplicatedSearchMode; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_NEIGHBORS_MG_LOAD_BALANCER` | `0` | +| `CUVS_NEIGHBORS_MG_ROUND_ROBIN` | `1` | + + +### cuvsMultiGpuShardedMergeMode + +Merge mode when using a sharded index + +```c +typedef enum { ... } cuvsMultiGpuShardedMergeMode; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_NEIGHBORS_MG_MERGE_ON_ROOT_RANK` | `0` | +| `CUVS_NEIGHBORS_MG_TREE_MERGE` | `1` | diff --git a/fern/pages/c_api/c-api-neighbors-mg-ivf-flat.md b/fern/pages/c_api/c-api-neighbors-mg-ivf-flat.md new file mode 100644 index 0000000000..a35cdef5b0 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-mg-ivf-flat.md @@ -0,0 +1,343 @@ +--- +slug: api-reference/c-api-neighbors-mg-ivf-flat +--- + +# Multi-GPU IVF Flat + +_Source header: `cuvs/neighbors/mg_ivf_flat.h`_ + +## Multi-GPU IVF-Flat index build parameters + + +### cuvsMultiGpuIvfFlatIndexParams + +Multi-GPU parameters to build IVF-Flat Index + +This structure extends the base IVF-Flat index parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuIvfFlatIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindexparams) | Base IVF-Flat index parameters | +| `mode` | [`cuvsMultiGpuDistributionMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpudistributionmode) | Distribution mode for multi-GPU setup | + + +### cuvsMultiGpuIvfFlatIndexParamsCreate + +Allocate Multi-GPU IVF-Flat Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatIndexParamsCreate(cuvsMultiGpuIvfFlatIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuIvfFlatIndexParams_t*`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindexparams) | cuvsMultiGpuIvfFlatIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfFlatIndexParamsDestroy + +De-allocate Multi-GPU IVF-Flat Index params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatIndexParamsDestroy(cuvsMultiGpuIvfFlatIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index search parameters + + +### cuvsMultiGpuIvfFlatSearchParams + +Multi-GPU parameters to search IVF-Flat index + +This structure extends the base IVF-Flat search parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuIvfFlatSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsIvfFlatSearchParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatsearchparams) | Base IVF-Flat search parameters | +| `search_mode` | [`cuvsMultiGpuReplicatedSearchMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpureplicatedsearchmode) | Replicated search mode | +| `merge_mode` | [`cuvsMultiGpuShardedMergeMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpushardedmergemode) | Sharded merge mode | +| `n_rows_per_batch` | `int64_t` | Number of rows per batch | + + +### cuvsMultiGpuIvfFlatSearchParamsCreate + +Allocate Multi-GPU IVF-Flat search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatSearchParamsCreate(cuvsMultiGpuIvfFlatSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuIvfFlatSearchParams_t*`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatsearchparams) | cuvsMultiGpuIvfFlatSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfFlatSearchParamsDestroy + +De-allocate Multi-GPU IVF-Flat search params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatSearchParamsDestroy(cuvsMultiGpuIvfFlatSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuIvfFlatSearchParams_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatsearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index + + +### cuvsMultiGpuIvfFlatIndex + +Struct to hold address of cuvs::neighbors::mg_index<ivf_flat::index> and its active + +trained dtype + +```c +typedef struct { ... } cuvsMultiGpuIvfFlatIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsMultiGpuIvfFlatIndexCreate + +Allocate Multi-GPU IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatIndexCreate(cuvsMultiGpuIvfFlatIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuIvfFlatIndex_t*`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | cuvsMultiGpuIvfFlatIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfFlatIndexDestroy + +De-allocate Multi-GPU IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatIndexDestroy(cuvsMultiGpuIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | cuvsMultiGpuIvfFlatIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index build + + +### cuvsMultiGpuIvfFlatBuild + +Build a Multi-GPU IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatBuild(cuvsResources_t res, +cuvsMultiGpuIvfFlatIndexParams_t params, +DLManagedTensor* dataset_tensor, +cuvsMultiGpuIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindexparams) | Multi-GPU IVF-Flat index parameters | +| `dataset_tensor` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index search + + +### cuvsMultiGpuIvfFlatSearch + +Search a Multi-GPU IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatSearch(cuvsResources_t res, +cuvsMultiGpuIvfFlatSearchParams_t params, +cuvsMultiGpuIvfFlatIndex_t index, +DLManagedTensor* queries_tensor, +DLManagedTensor* neighbors_tensor, +DLManagedTensor* distances_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuIvfFlatSearchParams_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatsearchparams) | Multi-GPU IVF-Flat search parameters | +| `index` | in | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index | +| `queries_tensor` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset | +| `neighbors_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output neighbors | +| `distances_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output distances | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index extend + + +### cuvsMultiGpuIvfFlatExtend + +Extend a Multi-GPU IVF-Flat index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatExtend(cuvsResources_t res, +cuvsMultiGpuIvfFlatIndex_t index, +DLManagedTensor* new_vectors_tensor, +DLManagedTensor* new_indices_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in,out | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index to extend | +| `new_vectors_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new vectors to add | +| `new_indices_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new indices (optional, can be NULL) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index serialize + + +### cuvsMultiGpuIvfFlatSerialize + +Serialize a Multi-GPU IVF-Flat index to file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatSerialize(cuvsResources_t res, +cuvsMultiGpuIvfFlatIndex_t index, +const char* filename); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index to serialize | +| `filename` | in | `const char*` | Path to the output file | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index deserialize + + +### cuvsMultiGpuIvfFlatDeserialize + +Deserialize a Multi-GPU IVF-Flat index from file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatDeserialize(cuvsResources_t res, +const char* filename, +cuvsMultiGpuIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the input file | +| `index` | out | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-Flat index distribute + + +### cuvsMultiGpuIvfFlatDistribute + +Distribute a local IVF-Flat index to create a Multi-GPU index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfFlatDistribute(cuvsResources_t res, +const char* filename, +cuvsMultiGpuIvfFlatIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the local index file | +| `index` | out | [`cuvsMultiGpuIvfFlatIndex_t`](/api-reference/c-api-neighbors-mg-ivf-flat#cuvsmultigpuivfflatindex) | Multi-GPU IVF-Flat index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-mg-ivf-pq.md b/fern/pages/c_api/c-api-neighbors-mg-ivf-pq.md new file mode 100644 index 0000000000..a53bf0c175 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-mg-ivf-pq.md @@ -0,0 +1,343 @@ +--- +slug: api-reference/c-api-neighbors-mg-ivf-pq +--- + +# Multi-GPU IVF PQ + +_Source header: `cuvs/neighbors/mg_ivf_pq.h`_ + +## Multi-GPU IVF-PQ index build parameters + + +### cuvsMultiGpuIvfPqIndexParams + +Multi-GPU parameters to build IVF-PQ Index + +This structure extends the base IVF-PQ index parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuIvfPqIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | Base IVF-PQ index parameters | +| `mode` | [`cuvsMultiGpuDistributionMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpudistributionmode) | Distribution mode for multi-GPU setup | + + +### cuvsMultiGpuIvfPqIndexParamsCreate + +Allocate Multi-GPU IVF-PQ Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqIndexParamsCreate(cuvsMultiGpuIvfPqIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuIvfPqIndexParams_t*`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindexparams) | cuvsMultiGpuIvfPqIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfPqIndexParamsDestroy + +De-allocate Multi-GPU IVF-PQ Index params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqIndexParamsDestroy(cuvsMultiGpuIvfPqIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsMultiGpuIvfPqIndexParams_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index search parameters + + +### cuvsMultiGpuIvfPqSearchParams + +Multi-GPU parameters to search IVF-PQ index + +This structure extends the base IVF-PQ search parameters with multi-GPU specific settings. + +```c +struct cuvsMultiGpuIvfPqSearchParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `base_params` | [`cuvsIvfPqSearchParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqsearchparams) | Base IVF-PQ search parameters | +| `search_mode` | [`cuvsMultiGpuReplicatedSearchMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpureplicatedsearchmode) | Replicated search mode | +| `merge_mode` | [`cuvsMultiGpuShardedMergeMode`](/api-reference/c-api-neighbors-mg-common#cuvsmultigpushardedmergemode) | Sharded merge mode | +| `n_rows_per_batch` | `int64_t` | Number of rows per batch | + + +### cuvsMultiGpuIvfPqSearchParamsCreate + +Allocate Multi-GPU IVF-PQ search params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqSearchParamsCreate(cuvsMultiGpuIvfPqSearchParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuIvfPqSearchParams_t*`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqsearchparams) | cuvsMultiGpuIvfPqSearchParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfPqSearchParamsDestroy + +De-allocate Multi-GPU IVF-PQ search params + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqSearchParamsDestroy(cuvsMultiGpuIvfPqSearchParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsMultiGpuIvfPqSearchParams_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqsearchparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index + + +### cuvsMultiGpuIvfPqIndex + +Struct to hold address of cuvs::neighbors::mg_index<ivf_pq::index> and its active trained + +dtype + +```c +typedef struct { ... } cuvsMultiGpuIvfPqIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsMultiGpuIvfPqIndexCreate + +Allocate Multi-GPU IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqIndexCreate(cuvsMultiGpuIvfPqIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuIvfPqIndex_t*`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | cuvsMultiGpuIvfPqIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsMultiGpuIvfPqIndexDestroy + +De-allocate Multi-GPU IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqIndexDestroy(cuvsMultiGpuIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | cuvsMultiGpuIvfPqIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index build + + +### cuvsMultiGpuIvfPqBuild + +Build a Multi-GPU IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqBuild(cuvsResources_t res, +cuvsMultiGpuIvfPqIndexParams_t params, +DLManagedTensor* dataset_tensor, +cuvsMultiGpuIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuIvfPqIndexParams_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindexparams) | Multi-GPU IVF-PQ index parameters | +| `dataset_tensor` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index search + + +### cuvsMultiGpuIvfPqSearch + +Search a Multi-GPU IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqSearch(cuvsResources_t res, +cuvsMultiGpuIvfPqSearchParams_t params, +cuvsMultiGpuIvfPqIndex_t index, +DLManagedTensor* queries_tensor, +DLManagedTensor* neighbors_tensor, +DLManagedTensor* distances_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsMultiGpuIvfPqSearchParams_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqsearchparams) | Multi-GPU IVF-PQ search parameters | +| `index` | in | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index | +| `queries_tensor` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset | +| `neighbors_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output neighbors | +| `distances_tensor` | out | `DLManagedTensor*` | DLManagedTensor* output distances | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index extend + + +### cuvsMultiGpuIvfPqExtend + +Extend a Multi-GPU IVF-PQ index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqExtend(cuvsResources_t res, +cuvsMultiGpuIvfPqIndex_t index, +DLManagedTensor* new_vectors_tensor, +DLManagedTensor* new_indices_tensor); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in,out | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index to extend | +| `new_vectors_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new vectors to add | +| `new_indices_tensor` | in | `DLManagedTensor*` | DLManagedTensor* new indices (optional, can be NULL) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index serialize + + +### cuvsMultiGpuIvfPqSerialize + +Serialize a Multi-GPU IVF-PQ index to file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqSerialize(cuvsResources_t res, +cuvsMultiGpuIvfPqIndex_t index, +const char* filename); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index` | in | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index to serialize | +| `filename` | in | `const char*` | Path to the output file | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index deserialize + + +### cuvsMultiGpuIvfPqDeserialize + +Deserialize a Multi-GPU IVF-PQ index from file + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqDeserialize(cuvsResources_t res, +const char* filename, +cuvsMultiGpuIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the input file | +| `index` | out | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Multi-GPU IVF-PQ index distribute + + +### cuvsMultiGpuIvfPqDistribute + +Distribute a local IVF-PQ index to create a Multi-GPU index + +```c +CUVS_EXPORT cuvsError_t cuvsMultiGpuIvfPqDistribute(cuvsResources_t res, +const char* filename, +cuvsMultiGpuIvfPqIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | Path to the local index file | +| `index` | out | [`cuvsMultiGpuIvfPqIndex_t`](/api-reference/c-api-neighbors-mg-ivf-pq#cuvsmultigpuivfpqindex) | Multi-GPU IVF-PQ index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-nn-descent.md b/fern/pages/c_api/c-api-neighbors-nn-descent.md new file mode 100644 index 0000000000..0f91d4f528 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-nn-descent.md @@ -0,0 +1,180 @@ +--- +slug: api-reference/c-api-neighbors-nn-descent +--- + +# NN Descent + +_Source header: `cuvs/neighbors/nn_descent.h`_ + +## Types + + +### cuvsNNDescentDistCompDtype + +Dtype to use for distance computation + +```c +typedef enum { ... } cuvsNNDescentDistCompDtype; +``` + +**Values** + +| Name | Value | Description | +| --- | --- | --- | +| `NND_DIST_COMP_AUTO` | `0` | Automatically determine the best dtype for distance computation based on the dataset dimensions. | +| `NND_DIST_COMP_FP32` | `1` | Use fp32 distance computation for better precision at the cost of performance and memory usage. | +| `NND_DIST_COMP_FP16` | `2` | Use fp16 distance computation. | + +## The nn-descent algorithm parameters. + + +### cuvsNNDescentIndexParams + +Parameters used to build an nn-descent index + +```c +struct cuvsNNDescentIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | The distance metric to use | +| `metric_arg` | `float` | The argument used by distance metrics like Minkowskidistance | +| `graph_degree` | `size_t` | For an input dataset of dimensions (N, D), determines the final dimensions of the all-neighbors knn graph which turns out to be of dimensions (N, graph_degree) | +| `intermediate_graph_degree` | `size_t` | Internally, nn-descent builds an all-neighbors knn graph of dimensions (N, intermediate_graph_degree) before selecting the final `graph_degree` neighbors. It's recommended that `intermediate_graph_degree` >= 1.5 * graph_degree | +| `max_iterations` | `size_t` | The number of iterations that nn-descent will refine the graph for. More iterations produce a better quality graph at cost of performance | +| `termination_threshold` | `float` | The delta at which nn-descent will terminate its iterations | +| `return_distances` | `bool` | Boolean to decide whether to return distances array | +| `dist_comp_dtype` | [`cuvsNNDescentDistCompDtype`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentdistcompdtype) | dtype to use for distance computation. Defaults to `NND_DIST_COMP_AUTO` which automatically determines the best dtype for distance computation based on the dataset dimensions. Use `NND_DIST_COMP_FP32` for better precision at the cost of performance and memory usage. This option is only valid when data type is fp32. Use `NND_DIST_COMP_FP16` for better performance and memory usage at the cost of precision. | + + +### cuvsNNDescentIndexParamsCreate + +Allocate NN-Descent Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsNNDescentIndexParamsCreate(cuvsNNDescentIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsNNDescentIndexParams_t*`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindexparams) | cuvsNNDescentIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsNNDescentIndexParamsDestroy + +De-allocate NN-Descent Index params + +```c +CUVS_EXPORT cuvsError_t cuvsNNDescentIndexParamsDestroy(cuvsNNDescentIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsNNDescentIndexParams_t`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## NN-Descent index + + +### cuvsNNDescentIndex + +Struct to hold address of cuvs::neighbors::nn_descent::index and its active trained dtype + +```c +typedef struct { ... } cuvsNNDescentIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsNNDescentIndexCreate + +Allocate NN-Descent index + +```c +CUVS_EXPORT cuvsError_t cuvsNNDescentIndexCreate(cuvsNNDescentIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsNNDescentIndex_t*`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindex) | cuvsNNDescentIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsNNDescentIndexDestroy + +De-allocate NN-Descent index + +```c +CUVS_EXPORT cuvsError_t cuvsNNDescentIndexDestroy(cuvsNNDescentIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsNNDescentIndex_t`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindex) | cuvsNNDescentIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## NN-Descent index build + + +### cuvsNNDescentBuild + +Build a NN-Descent index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsNNDescentBuild(cuvsResources_t res, +cuvsNNDescentIndexParams_t index_params, +DLManagedTensor* dataset, +DLManagedTensor* graph, +cuvsNNDescentIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` +3. `kDLDataType.code == kDLInt` and `kDLDataType.bits = 8` +4. `kDLDataType.code == kDLUInt` and `kDLDataType.bits = 8` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index_params` | in | [`cuvsNNDescentIndexParams_t`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindexparams) | cuvsNNDescentIndexParams_t used to build NN-Descent index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset on host or device memory | +| `graph` | inout | `DLManagedTensor*` | Optional preallocated graph on host memory to store output | +| `index` | out | [`cuvsNNDescentIndex_t`](/api-reference/c-api-neighbors-nn-descent#cuvsnndescentindex) | cuvsNNDescentIndex_t Newly built NN-Descent index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-refine.md b/fern/pages/c_api/c-api-neighbors-refine.md new file mode 100644 index 0000000000..eea9d78518 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-refine.md @@ -0,0 +1,42 @@ +--- +slug: api-reference/c-api-neighbors-refine +--- + +# Refine + +_Source header: `cuvs/neighbors/refine.h`_ + +## Approximate Nearest Neighbors Refinement C-API + + +### cuvsRefine + +Refine nearest neighbor search. + +```c +CUVS_EXPORT cuvsError_t cuvsRefine(cuvsResources_t res, +DLManagedTensor* dataset, +DLManagedTensor* queries, +DLManagedTensor* candidates, +cuvsDistanceType metric, +DLManagedTensor* indices, +DLManagedTensor* distances); +``` + +Refinement is an operation that follows an approximate NN search. The approximate search has already selected n_candidates neighbor candidates for each query. We narrow it down to k neighbors. For each query, we calculate the exact distance between the query and its n_candidates neighbor candidate, and select the k nearest ones. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `dataset` | in | `DLManagedTensor*` | device matrix that stores the dataset [n_rows, dims] | +| `queries` | in | `DLManagedTensor*` | device matrix of the queries [n_queris, dims] | +| `candidates` | in | `DLManagedTensor*` | indices of candidate vectors [n_queries, n_candidates], where n_candidates >= k | +| `metric` | in | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | distance metric to use. Euclidean (L2) is used by default | +| `indices` | out | `DLManagedTensor*` | device matrix that stores the refined indices [n_queries, k] | +| `distances` | out | `DLManagedTensor*` | device matrix that stores the refined distances [n_queries, k] | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-tiered-index.md b/fern/pages/c_api/c-api-neighbors-tiered-index.md new file mode 100644 index 0000000000..914543863c --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-tiered-index.md @@ -0,0 +1,267 @@ +--- +slug: api-reference/c-api-neighbors-tiered-index +--- + +# Tiered Index + +_Source header: `cuvs/neighbors/tiered_index.h`_ + +## Types + + +### cuvsTieredIndexANNAlgo + +Enum to hold which ANN algorithm is being used in the tiered index + +```c +typedef enum { ... } cuvsTieredIndexANNAlgo; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_TIERED_INDEX_ALGO_CAGRA` | `0` | +| `CUVS_TIERED_INDEX_ALGO_IVF_FLAT` | `1` | +| `CUVS_TIERED_INDEX_ALGO_IVF_PQ` | `2` | + +## Tiered Index + + +### cuvsTieredIndex + +Struct to hold address of cuvs::neighbors::tiered_index::index and its active trained + +dtype + +```c +typedef struct { ... } cuvsTieredIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | +| `algo` | [`cuvsTieredIndexANNAlgo`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexannalgo) | | + + +### cuvsTieredIndexCreate + +Allocate Tiered Index + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexCreate(cuvsTieredIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsTieredIndex_t*`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | cuvsTieredIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsTieredIndexDestroy + +De-allocate Tiered index + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexDestroy(cuvsTieredIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsTieredIndex_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | cuvsTieredIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Tiered Index build parameters + + +### cuvsTieredIndexParams + +Supplemental parameters to build a TieredIndex + +```c +struct cuvsTieredIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance type. | +| `algo` | [`cuvsTieredIndexANNAlgo`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexannalgo) | The type of ANN algorithm we are using | +| `min_ann_rows` | `int64_t` | The minimum number of rows necessary in the index to create an ann index | +| `create_ann_index_on_extend` | `bool` | Whether or not to create a new ann index on extend, if the number of rows in the incremental (bfknn) portion is above min_ann_rows | +| `cagra_params` | [`cuvsCagraIndexParams_t`](/api-reference/c-api-neighbors-cagra#cuvscagraindexparams) | Optional parameters for building a cagra index | +| `ivf_flat_params` | [`cuvsIvfFlatIndexParams_t`](/api-reference/c-api-neighbors-ivf-flat#cuvsivfflatindexparams) | Optional parameters for building a ivf_flat index | +| `ivf_pq_params` | [`cuvsIvfPqIndexParams_t`](/api-reference/c-api-neighbors-ivf-pq#cuvsivfpqindexparams) | Optional parameters for building a ivf-pq index | + + +### cuvsTieredIndexParamsCreate + +Allocate Tiered Index Params and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexParamsCreate(cuvsTieredIndexParams_t* index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsTieredIndexParams_t*`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexparams) | cuvsTieredIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsTieredIndexParamsDestroy + +De-allocate Tiered Index params + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexParamsDestroy(cuvsTieredIndexParams_t index_params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index_params` | in | [`cuvsTieredIndexParams_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Tiered index build + + +### cuvsTieredIndexBuild + +Build a TieredIndex index with a `DLManagedTensor` which has underlying + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexBuild(cuvsResources_t res, +cuvsTieredIndexParams_t index_params, +DLManagedTensor* dataset, +cuvsTieredIndex_t index); +``` + +`DLDeviceType` equal to `kDLCUDA`, `kDLCUDAHost`, `kDLCUDAManaged`, or `kDLCPU`. Also, acceptable underlying types are: + +1. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 32` +2. `kDLDataType.code == kDLFloat` and `kDLDataType.bits = 16` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index_params` | in | [`cuvsTieredIndexParams_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexparams) | Index parameters to use when building the index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsTieredIndex_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | cuvsTieredIndex_t Newly built TieredIndex index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Tiered index search + + +### cuvsTieredIndexSearch + +Search a TieredIndex index with a `DLManagedTensor` + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexSearch(cuvsResources_t res, +void* search_params, +cuvsTieredIndex_t index, +DLManagedTensor* queries, +DLManagedTensor* neighbors, +DLManagedTensor* distances, +cuvsFilter prefilter); +``` + +cuvsCagraSearchParams_t, cuvsIvfFlatSearchParams_t, cuvsIvfPqSearchParams_t depending on the type of the tiered index used + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `search_params` | in | `void*` | params used to the ANN index, should be one of | +| `index` | in | [`cuvsTieredIndex_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | cuvsTieredIndex which has been returned by `cuvsTieredIndexBuild` | +| `queries` | in | `DLManagedTensor*` | DLManagedTensor* queries dataset to search | +| `neighbors` | out | `DLManagedTensor*` | DLManagedTensor* output `k` neighbors for queries | +| `distances` | out | `DLManagedTensor*` | DLManagedTensor* output `k` distances for queries | +| `prefilter` | in | [`cuvsFilter`](/api-reference/c-api-neighbors-common#cuvsfilter) | cuvsFilter input prefilter that can be used to filter queries and neighbors based on the given bitmap. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Tiered index extend + + +### cuvsTieredIndexExtend + +Extend the index with the new data. + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexExtend(cuvsResources_t res, +DLManagedTensor* new_vectors, +cuvsTieredIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `new_vectors` | in | `DLManagedTensor*` | DLManagedTensor* the new vectors to add to the index | +| `index` | inout | [`cuvsTieredIndex_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | Tiered index to be extended | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Tiered index merge + + +### cuvsTieredIndexMerge + +Merge multiple indices together into a single index + +```c +CUVS_EXPORT cuvsError_t cuvsTieredIndexMerge(cuvsResources_t res, +cuvsTieredIndexParams_t index_params, +cuvsTieredIndex_t* indices, +size_t num_indices, +cuvsTieredIndex_t output_index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `index_params` | in | [`cuvsTieredIndexParams_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindexparams) | Index parameters to use when merging | +| `indices` | in | [`cuvsTieredIndex_t*`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | pointers to indices to merge together | +| `num_indices` | in | `size_t` | the number of indices to merge | +| `output_index` | out | [`cuvsTieredIndex_t`](/api-reference/c-api-neighbors-tiered-index#cuvstieredindex) | the merged index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-neighbors-vamana.md b/fern/pages/c_api/c-api-neighbors-vamana.md new file mode 100644 index 0000000000..7863bb5f80 --- /dev/null +++ b/fern/pages/c_api/c-api-neighbors-vamana.md @@ -0,0 +1,214 @@ +--- +slug: api-reference/c-api-neighbors-vamana +--- + +# Vamana + +_Source header: `cuvs/neighbors/vamana.h`_ + +## C API for Vamana index build + + +### cuvsVamanaIndexParams + +Supplemental parameters to build Vamana Index + +```c +struct cuvsVamanaIndexParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvsDistanceType`](/api-reference/c-api-distance-distance#cuvsdistancetype) | Distance type. | +| `graph_degree` | `uint32_t` | Maximum degree of graph; corresponds to the R parameter of Vamana algorithm in the literature. | +| `visited_size` | `uint32_t` | Maximum number of visited nodes per search during Vamana algorithm. Loosely corresponds to the L parameter in the literature. | +| `vamana_iters` | `float` | The number of times all vectors are inserted into the graph. If > 1, all vectors are re-inserted to improve graph quality. | +| `alpha` | `float` | Used to determine how aggressive the pruning will be. | +| `max_fraction` | `float` | The maximum batch size is this fraction of the total dataset size. Larger gives faster build but lower graph quality. | +| `batch_base` | `float` | Base of growth rate of batch sizes * | +| `queue_size` | `uint32_t` | Size of candidate queue structure - should be (2^x)-1 | +| `reverse_batchsize` | `uint32_t` | Max batchsize of reverse edge processing (reduces memory footprint) | + + +### cuvsVamanaIndexParamsCreate + +Allocate Vamana Index params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaIndexParamsCreate(cuvsVamanaIndexParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsVamanaIndexParams_t*`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindexparams) | cuvsVamanaIndexParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsVamanaIndexParamsDestroy + +De-allocate Vamana Index params + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaIndexParamsDestroy(cuvsVamanaIndexParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsVamanaIndexParams_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindexparams) | cuvsVamanaIndexParams_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Vamana index + + +### cuvsVamanaIndex + +Struct to hold address of cuvs::neighbors::vamana::index and its active trained dtype + +```c +typedef struct { ... } cuvsVamanaIndex; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsVamanaIndexCreate + +Allocate Vamana index + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaIndexCreate(cuvsVamanaIndex_t* index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsVamanaIndex_t*`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindex) | cuvsVamanaIndex_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsVamanaIndexDestroy + +De-allocate Vamana index + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaIndexDestroy(cuvsVamanaIndex_t index); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsVamanaIndex_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindex) | cuvsVamanaIndex_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsVamanaIndexGetDims + +Get the dimension of the index + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaIndexGetDims(cuvsVamanaIndex_t index, int* dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `index` | in | [`cuvsVamanaIndex_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindex) | cuvsVamanaIndex_t to get dimension of | +| `dim` | out | `int*` | pointer to dimension to set | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Vamana index build + + +### cuvsVamanaBuild + +Build Vamana index + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaBuild(cuvsResources_t res, +cuvsVamanaIndexParams_t params, +DLManagedTensor* dataset, +cuvsVamanaIndex_t index); +``` + +Build the index from the dataset for efficient DiskANN search. + +The build uses the Vamana insertion-based algorithm to create the graph. The algorithm starts with an empty graph and iteratively inserts batches of nodes. Each batch involves performing a greedy search for each vector to be inserted, and inserting it with edges to all nodes traversed during the search. Reverse edges are also inserted and robustPrune is applied to improve graph quality. The index_params struct controls the degree of the final graph. + +The following distance metrics are supported: + +- L2 + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsVamanaIndexParams_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindexparams) | cuvsVamanaIndexParams_t used to build Vamana index | +| `dataset` | in | `DLManagedTensor*` | DLManagedTensor* training dataset | +| `index` | out | [`cuvsVamanaIndex_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindex) | cuvsVamanaIndex_t Vamana index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + +## Vamana index serialize + + +### cuvsVamanaSerialize + +Save Vamana index to file + +```c +CUVS_EXPORT cuvsError_t cuvsVamanaSerialize(cuvsResources_t res, +const char* filename, +cuvsVamanaIndex_t index, +bool include_dataset); +``` + +Matches the file format used by the DiskANN open-source repository, allowing cross-compatibility. + +Serialized Index is to be used by the DiskANN open-source repository for graph search. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `filename` | in | `const char*` | the file prefix for where the index is saved | +| `index` | in | [`cuvsVamanaIndex_t`](/api-reference/c-api-neighbors-vamana#cuvsvamanaindex) | cuvsVamanaIndex_t to serialize | +| `include_dataset` | in | `bool` | whether to include the dataset in the serialized index | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-preprocessing-pca.md b/fern/pages/c_api/c-api-preprocessing-pca.md new file mode 100644 index 0000000000..0a936e2d33 --- /dev/null +++ b/fern/pages/c_api/c-api-preprocessing-pca.md @@ -0,0 +1,229 @@ +--- +slug: api-reference/c-api-preprocessing-pca +--- + +# PCA + +_Source header: `cuvs/preprocessing/pca.h`_ + +## C API for PCA (Principal Component Analysis) + + +### cuvsPcaSolver + +Solver algorithm for PCA eigen decomposition. + +```c +enum cuvsPcaSolver { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `CUVS_PCA_COV_EIG_DQ` | `0` | +| `CUVS_PCA_COV_EIG_JACOBI` | `1` | + + +### cuvsPcaParams + +Parameters for PCA decomposition. + +```c +struct cuvsPcaParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_components` | `int` | Number of principal components to keep. | +| `copy` | `bool` | If false, data passed to fit are overwritten and running fit(X).transform(X) will not yield the expected results; use fit_transform(X) instead. | +| `whiten` | `bool` | When true the component vectors are multiplied by the square root of n_samples and then divided by the singular values to ensure uncorrelated outputs with unit component-wise variances. | +| `algorithm` | [`enum cuvsPcaSolver`](/api-reference/c-api-preprocessing-pca#cuvspcasolver) | Solver algorithm to use. | +| `tol` | `float` | Tolerance for singular values (used by Jacobi solver). | +| `n_iterations` | `int` | Number of iterations for the power method (Jacobi solver). | + + +### cuvsPcaParamsCreate + +Allocate PCA params and populate with default values. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaParamsCreate(cuvsPcaParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | out | [`cuvsPcaParams_t*`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | cuvsPcaParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsPcaParamsDestroy + +De-allocate PCA params. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaParamsDestroy(cuvsPcaParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsPcaParams_t`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | cuvsPcaParams_t to de-allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsPcaFit + +Perform PCA fit operation. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaFit(cuvsResources_t res, +cuvsPcaParams_t params, +DLManagedTensor* input, +DLManagedTensor* components, +DLManagedTensor* explained_var, +DLManagedTensor* explained_var_ratio, +DLManagedTensor* singular_vals, +DLManagedTensor* mu, +DLManagedTensor* noise_vars, +bool flip_signs_based_on_U); +``` + +Computes the principal components, explained variances, singular values, and column means from the input data. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsPcaParams_t`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | PCA parameters | +| `input` | inout | `DLManagedTensor*` | input data [n_rows x n_cols] (col-major, float32, device) | +| `components` | out | `DLManagedTensor*` | principal components [n_components x n_cols] (col-major, float32, device) | +| `explained_var` | out | `DLManagedTensor*` | explained variances [n_components] (float32, device) | +| `explained_var_ratio` | out | `DLManagedTensor*` | explained variance ratios [n_components] (float32, device) | +| `singular_vals` | out | `DLManagedTensor*` | singular values [n_components] (float32, device) | +| `mu` | out | `DLManagedTensor*` | column means [n_cols] (float32, device) | +| `noise_vars` | out | `DLManagedTensor*` | noise variance [1] (float32, device) | +| `flip_signs_based_on_U` | in | `bool` | whether to determine signs by U (true) or V.T (false) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsPcaFitTransform + +Perform PCA fit and transform in a single operation. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaFitTransform(cuvsResources_t res, +cuvsPcaParams_t params, +DLManagedTensor* input, +DLManagedTensor* trans_input, +DLManagedTensor* components, +DLManagedTensor* explained_var, +DLManagedTensor* explained_var_ratio, +DLManagedTensor* singular_vals, +DLManagedTensor* mu, +DLManagedTensor* noise_vars, +bool flip_signs_based_on_U); +``` + +Computes the principal components and transforms the input data into the eigenspace. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsPcaParams_t`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | PCA parameters | +| `input` | inout | `DLManagedTensor*` | input data [n_rows x n_cols] (col-major, float32, device) | +| `trans_input` | out | `DLManagedTensor*` | transformed data [n_rows x n_components] (col-major, float32, device) | +| `components` | out | `DLManagedTensor*` | principal components [n_components x n_cols] (col-major, float32, device) | +| `explained_var` | out | `DLManagedTensor*` | explained variances [n_components] (float32, device) | +| `explained_var_ratio` | out | `DLManagedTensor*` | explained variance ratios [n_components] (float32, device) | +| `singular_vals` | out | `DLManagedTensor*` | singular values [n_components] (float32, device) | +| `mu` | out | `DLManagedTensor*` | column means [n_cols] (float32, device) | +| `noise_vars` | out | `DLManagedTensor*` | noise variance [1] (float32, device) | +| `flip_signs_based_on_U` | in | `bool` | whether to determine signs by U (true) or V.T (false) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsPcaTransform + +Perform PCA transform operation. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaTransform(cuvsResources_t res, +cuvsPcaParams_t params, +DLManagedTensor* input, +DLManagedTensor* components, +DLManagedTensor* singular_vals, +DLManagedTensor* mu, +DLManagedTensor* trans_input); +``` + +Transforms the input data into the eigenspace using previously computed principal components. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsPcaParams_t`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | PCA parameters | +| `input` | inout | `DLManagedTensor*` | data to transform [n_rows x n_cols] (col-major, float32, device) | +| `components` | in | `DLManagedTensor*` | principal components [n_components x n_cols] (col-major, float32, device) | +| `singular_vals` | in | `DLManagedTensor*` | singular values [n_components] (float32, device) | +| `mu` | in | `DLManagedTensor*` | column means [n_cols] (float32, device) | +| `trans_input` | out | `DLManagedTensor*` | transformed data [n_rows x n_components] (col-major, float32, device) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsPcaInverseTransform + +Perform PCA inverse transform operation. + +```c +CUVS_EXPORT cuvsError_t cuvsPcaInverseTransform(cuvsResources_t res, +cuvsPcaParams_t params, +DLManagedTensor* trans_input, +DLManagedTensor* components, +DLManagedTensor* singular_vals, +DLManagedTensor* mu, +DLManagedTensor* output); +``` + +Transforms data from the eigenspace back to the original space. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | cuvsResources_t opaque C handle | +| `params` | in | [`cuvsPcaParams_t`](/api-reference/c-api-preprocessing-pca#cuvspcaparams) | PCA parameters | +| `trans_input` | in | `DLManagedTensor*` | transformed data [n_rows x n_components] (col-major, float32, device) | +| `components` | in | `DLManagedTensor*` | principal components [n_components x n_cols] (col-major, float32, device) | +| `singular_vals` | in | `DLManagedTensor*` | singular values [n_components] (float32, device) | +| `mu` | in | `DLManagedTensor*` | column means [n_cols] (float32, device) | +| `output` | out | `DLManagedTensor*` | reconstructed data [n_rows x n_cols] (col-major, float32, device) | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-preprocessing-quantize-binary.md b/fern/pages/c_api/c-api-preprocessing-quantize-binary.md new file mode 100644 index 0000000000..9005fd2ec8 --- /dev/null +++ b/fern/pages/c_api/c-api-preprocessing-quantize-binary.md @@ -0,0 +1,215 @@ +--- +slug: api-reference/c-api-preprocessing-quantize-binary +--- + +# Binary + +_Source header: `cuvs/preprocessing/quantize/binary.h`_ + +## C API for Binary Quantizer + + +### cuvsBinaryQuantizerThreshold + +In the cuvsBinaryQuantizerTransform function, a bit is set if the corresponding element in + +the dataset vector is greater than the corresponding element in the threshold vector. The mean and sampling_median thresholds are calculated separately for each dimension. + +```c +enum cuvsBinaryQuantizerThreshold { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `ZERO` | `0` | +| `MEAN` | `1` | +| `SAMPLING_MEDIAN` | `2` | + + +### cuvsBinaryQuantizerParams + +Binary quantizer parameters. + +```c +struct cuvsBinaryQuantizerParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `threshold` | [`/* * specifies the threshold to set a bit in cuvsBinaryQuantizerTransform */ enum cuvsBinaryQuantizerThreshold`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizerthreshold) | | +| `sampling_ratio` | `/* * specifies the sampling ratio */ float` | | + + +### cuvsBinaryQuantizerParamsCreate + +Allocate Binary Quantizer params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerParamsCreate(cuvsBinaryQuantizerParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsBinaryQuantizerParams_t*`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizerparams) | cuvsBinaryQuantizerParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizerParamsDestroy + +De-allocate Binary Quantizer params + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerParamsDestroy(cuvsBinaryQuantizerParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsBinaryQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizerparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizer + +Defines and stores threshold for quantization upon training + +The quantization is performed by a linear mapping of an interval in the float data type to the full range of the quantized int type. + +```c +typedef struct { ... } cuvsBinaryQuantizer; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsBinaryQuantizerCreate + +Allocate Binary Quantizer and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerCreate(cuvsBinaryQuantizer_t* quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsBinaryQuantizer_t*`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizer) | cuvsBinaryQuantizer_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizerDestroy + +De-allocate Binary Quantizer + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerDestroy(cuvsBinaryQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsBinaryQuantizer_t`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizer) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizerTrain + +Trains a binary quantizer to be used later for quantizing the dataset. + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerTrain(cuvsResources_t res, +cuvsBinaryQuantizerParams_t params, +DLManagedTensor* dataset, +cuvsBinaryQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `params` | in | [`cuvsBinaryQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizerparams) | configure binary quantizer, e.g. threshold | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix | +| `quantizer` | out | [`cuvsBinaryQuantizer_t`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizer) | trained binary quantizer | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizerTransform + +Applies binary quantization transform to the given dataset + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerTransform(cuvsResources_t res, +DLManagedTensor* dataset, +DLManagedTensor* out); +``` + +This applies binary quantization to a dataset, changing any positive values to a bitwise 1. This is useful for searching with the BitwiseHamming distance type. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix to transform | +| `out` | out | `DLManagedTensor*` | a row-major host or device matrix to store transformed data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsBinaryQuantizerTransformWithParams + +Applies binary quantization transform to the given dataset + +```c +CUVS_EXPORT cuvsError_t cuvsBinaryQuantizerTransformWithParams(cuvsResources_t res, +cuvsBinaryQuantizer_t quantizer, +DLManagedTensor* dataset, +DLManagedTensor* out); +``` + +This applies binary quantization to a dataset, changing any values that are larger than the threshold specified in the param to a bitwise 1. This is useful for searching with the BitwiseHamming distance type. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `quantizer` | in | [`cuvsBinaryQuantizer_t`](/api-reference/c-api-preprocessing-quantize-binary#cuvsbinaryquantizer) | binary quantizer | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix to transform | +| `out` | out | `DLManagedTensor*` | a row-major host or device matrix to store transformed data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-preprocessing-quantize-pq.md b/fern/pages/c_api/c-api-preprocessing-quantize-pq.md new file mode 100644 index 0000000000..c4a4bc9a14 --- /dev/null +++ b/fern/pages/c_api/c-api-preprocessing-quantize-pq.md @@ -0,0 +1,332 @@ +--- +slug: api-reference/c-api-preprocessing-quantize-pq +--- + +# PQ + +_Source header: `cuvs/preprocessing/quantize/pq.h`_ + +## C API for Product Quantizer + + +### cuvsProductQuantizerParams + +Product quantizer parameters. + +```c +struct cuvsProductQuantizerParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `pq_bits` | `uint32_t` | The bit length of the vector element after compression by PQ. Possible values: within [4, 16]. Hint: the smaller the 'pq_bits', the smaller the index size and the better the search performance, but the lower the recall. | +| `pq_dim` | `uint32_t` | The dimensionality of the vector after compression by PQ. When zero, an optimal value is selected using a heuristic. TODO: at the moment `dim` must be a multiple `pq_dim`. | +| `use_subspaces` | `bool` | Whether to use subspaces for product quantization (PQ). When true, one PQ codebook is used for each subspace. Otherwise, a single PQ codebook is used. | +| `use_vq` | `bool` | Whether to use Vector Quantization (KMeans) before product quantization (PQ). When true, VQ is used before PQ. When false, only product quantization is used. | +| `vq_n_centers` | `uint32_t` | Vector Quantization (VQ) codebook size - number of "coarse cluster centers". When zero, an optimal value is selected using a heuristic. When one, only product quantization is used. | +| `kmeans_n_iters` | `uint32_t` | The number of iterations searching for kmeans centers (both VQ & PQ phases). | +| `pq_kmeans_type` | [`cuvsKMeansType`](/api-reference/c-api-cluster-kmeans#cuvskmeanstype) | The type of kmeans algorithm to use for PQ training. | +| `max_train_points_per_pq_code` | `uint32_t` | The max number of data points to use per PQ code during PQ codebook training. Using more data points per PQ code may increase the quality of PQ codebook but may also increase the build time. We will use `pq_n_centers * max_train_points_per_pq_code` training points to train each PQ codebook. | +| `max_train_points_per_vq_cluster` | `uint32_t` | The max number of data points to use per VQ cluster. | + + +### cuvsProductQuantizerParamsCreate + +Allocate Product Quantizer params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerParamsCreate(cuvsProductQuantizerParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsProductQuantizerParams_t*`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizerparams) | cuvsProductQuantizerParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerParamsDestroy + +De-allocate Product Quantizer params + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerParamsDestroy(cuvsProductQuantizerParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsProductQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizerparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizer + +Defines and stores product quantizer upon training + +The quantization is performed by a linear mapping of an interval in the float data type to the full range of the quantized int type. + +```c +typedef struct { ... } cuvsProductQuantizer; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `addr` | `uintptr_t` | | +| `dtype` | `DLDataType` | | + + +### cuvsProductQuantizerCreate + +Allocate Product Quantizer + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerCreate(cuvsProductQuantizer_t* quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t*`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | cuvsProductQuantizer_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerDestroy + +De-allocate Product Quantizer + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerDestroy(cuvsProductQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerBuild + +Builds a product quantizer to be used later for quantizing the dataset. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerBuild(cuvsResources_t res, +cuvsProductQuantizerParams_t params, +DLManagedTensor* dataset, +cuvsProductQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `params` | in | [`cuvsProductQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizerparams) | Parameters for product quantizer training | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix | +| `quantizer` | out | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | trained product quantizer | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerTransform + +Applies product quantization transform to the given dataset + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerTransform(cuvsResources_t res, +cuvsProductQuantizer_t quantizer, +DLManagedTensor* dataset, +DLManagedTensor* codes_out, +DLManagedTensor* vq_labels); +``` + +This applies product quantization to a dataset. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix to transform | +| `codes_out` | out | `DLManagedTensor*` | a row-major device matrix to store transformed data | +| `vq_labels` | out | `DLManagedTensor*` | a device vector to store VQ labels. Optional, can be NULL. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerInverseTransform + +Applies product quantization inverse transform to the given quantized codes + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerInverseTransform(cuvsResources_t res, +cuvsProductQuantizer_t quantizer, +DLManagedTensor* pq_codes, +DLManagedTensor* out, +DLManagedTensor* vq_labels); +``` + +This applies product quantization inverse transform to the given quantized codes. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `pq_codes` | in | `DLManagedTensor*` | a row-major device matrix of quantized codes | +| `out` | out | `DLManagedTensor*` | a row-major device matrix to store the original data | +| `vq_labels` | out | `DLManagedTensor*` | a device vector containing the VQ labels when VQ is used. Optional, can be NULL. | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetPqBits + +Get the bit length of the vector element after compression by PQ. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetPqBits(cuvsProductQuantizer_t quantizer, uint32_t* pq_bits); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `pq_bits` | out | `uint32_t*` | bit length of the vector element after compression by PQ | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetPqDim + +Get the dimensionality of the vector after compression by PQ. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetPqDim(cuvsProductQuantizer_t quantizer, uint32_t* pq_dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `pq_dim` | out | `uint32_t*` | dimensionality of the vector after compression by PQ | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetPqCodebook + +Get the PQ codebook. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetPqCodebook(cuvsProductQuantizer_t quantizer, +DLManagedTensor* pq_codebook); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `pq_codebook` | out | `DLManagedTensor*` | PQ codebook | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetVqCodebook + +Get the VQ codebook. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetVqCodebook(cuvsProductQuantizer_t quantizer, +DLManagedTensor* vq_codebook); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `vq_codebook` | out | `DLManagedTensor*` | VQ codebook | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetEncodedDim + +Get the encoded dimension of the quantized dataset. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetEncodedDim(cuvsProductQuantizer_t quantizer, +uint32_t* encoded_dim); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `encoded_dim` | out | `uint32_t*` | encoded dimension of the quantized dataset | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsProductQuantizerGetUseVq + +Get whether VQ is used. + +```c +CUVS_EXPORT cuvsError_t cuvsProductQuantizerGetUseVq(cuvsProductQuantizer_t quantizer, bool* use_vq); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsProductQuantizer_t`](/api-reference/c-api-preprocessing-quantize-pq#cuvsproductquantizer) | product quantizer | +| `use_vq` | out | `bool*` | whether VQ is used | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/c-api-preprocessing-quantize-scalar.md b/fern/pages/c_api/c-api-preprocessing-quantize-scalar.md new file mode 100644 index 0000000000..5a3054d223 --- /dev/null +++ b/fern/pages/c_api/c-api-preprocessing-quantize-scalar.md @@ -0,0 +1,189 @@ +--- +slug: api-reference/c-api-preprocessing-quantize-scalar +--- + +# Scalar + +_Source header: `cuvs/preprocessing/quantize/scalar.h`_ + +## C API for Scalar Quantizer + + +### cuvsScalarQuantizerParams + +Scalar quantizer parameters. + +```c +struct cuvsScalarQuantizerParams { ... }; +``` + + +### cuvsScalarQuantizerParamsCreate + +Allocate Scalar Quantizer params, and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerParamsCreate(cuvsScalarQuantizerParams_t* params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsScalarQuantizerParams_t*`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizerparams) | cuvsScalarQuantizerParams_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizerParamsDestroy + +De-allocate Scalar Quantizer params + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerParamsDestroy(cuvsScalarQuantizerParams_t params); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `params` | in | [`cuvsScalarQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizerparams) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizer + +Defines and stores scalar for quantisation upon training + +The quantization is performed by a linear mapping of an interval in the float data type to the full range of the quantized int type. + +```c +typedef struct { ... } cuvsScalarQuantizer; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `min_` | `double` | | +| `max_` | `double` | | + + +### cuvsScalarQuantizerCreate + +Allocate Scalar Quantizer and populate with default values + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerCreate(cuvsScalarQuantizer_t* quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsScalarQuantizer_t*`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizer) | cuvsScalarQuantizer_t to allocate | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizerDestroy + +De-allocate Scalar Quantizer + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerDestroy(cuvsScalarQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `quantizer` | in | [`cuvsScalarQuantizer_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizer) | | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizerTrain + +Trains a scalar quantizer to be used later for quantizing the dataset. + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerTrain(cuvsResources_t res, +cuvsScalarQuantizerParams_t params, +DLManagedTensor* dataset, +cuvsScalarQuantizer_t quantizer); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `params` | in | [`cuvsScalarQuantizerParams_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizerparams) | configure scalar quantizer, e.g. quantile | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix | +| `quantizer` | out | [`cuvsScalarQuantizer_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizer) | trained scalar quantizer | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizerTransform + +Applies quantization transform to given dataset + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerTransform(cuvsResources_t res, +cuvsScalarQuantizer_t quantizer, +DLManagedTensor* dataset, +DLManagedTensor* out); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `quantizer` | in | [`cuvsScalarQuantizer_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizer) | a scalar quantizer | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix to transform | +| `out` | out | `DLManagedTensor*` | a row-major host or device matrix to store transformed data | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) + + +### cuvsScalarQuantizerInverseTransform + +Perform inverse quantization step on previously quantized dataset + +```c +CUVS_EXPORT cuvsError_t cuvsScalarQuantizerInverseTransform(cuvsResources_t res, +cuvsScalarQuantizer_t quantizer, +DLManagedTensor* dataset, +DLManagedTensor* out); +``` + +Note that depending on the chosen data types train dataset the conversion is not lossless. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | [`cuvsResources_t`](/api-reference/c-api-core-c-api#cuvsresources-t) | raft resource | +| `quantizer` | in | [`cuvsScalarQuantizer_t`](/api-reference/c-api-preprocessing-quantize-scalar#cuvsscalarquantizer) | a scalar quantizer | +| `dataset` | in | `DLManagedTensor*` | a row-major host or device matrix | +| `out` | out | `DLManagedTensor*` | a row-major host or device matrix | + +**Returns** + +[`CUVS_EXPORT cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t) diff --git a/fern/pages/c_api/index.md b/fern/pages/c_api/index.md new file mode 100644 index 0000000000..61d672ba91 --- /dev/null +++ b/fern/pages/c_api/index.md @@ -0,0 +1,27 @@ +# C API Documentation + +These pages are generated from the documented public headers in the cuVS source tree. + +- [K-Means](/api-reference/c-api-cluster-kmeans) +- [C API](/api-reference/c-api-core-c-api) +- [Distance](/api-reference/c-api-distance-distance) +- [Pairwise Distance](/api-reference/c-api-distance-pairwise-distance) +- [All Neighbors](/api-reference/c-api-neighbors-all-neighbors) +- [Brute Force](/api-reference/c-api-neighbors-brute-force) +- [Cagra](/api-reference/c-api-neighbors-cagra) +- [Common](/api-reference/c-api-neighbors-common) +- [HNSW](/api-reference/c-api-neighbors-hnsw) +- [IVF Flat](/api-reference/c-api-neighbors-ivf-flat) +- [IVF PQ](/api-reference/c-api-neighbors-ivf-pq) +- [Multi-GPU Cagra](/api-reference/c-api-neighbors-mg-cagra) +- [Multi-GPU Common](/api-reference/c-api-neighbors-mg-common) +- [Multi-GPU IVF Flat](/api-reference/c-api-neighbors-mg-ivf-flat) +- [Multi-GPU IVF PQ](/api-reference/c-api-neighbors-mg-ivf-pq) +- [NN Descent](/api-reference/c-api-neighbors-nn-descent) +- [Refine](/api-reference/c-api-neighbors-refine) +- [Tiered Index](/api-reference/c-api-neighbors-tiered-index) +- [Vamana](/api-reference/c-api-neighbors-vamana) +- [PCA](/api-reference/c-api-preprocessing-pca) +- [Binary](/api-reference/c-api-preprocessing-quantize-binary) +- [PQ](/api-reference/c-api-preprocessing-quantize-pq) +- [Scalar](/api-reference/c-api-preprocessing-quantize-scalar) diff --git a/fern/pages/c_guidelines.md b/fern/pages/c_guidelines.md new file mode 100644 index 0000000000..0388d99701 --- /dev/null +++ b/fern/pages/c_guidelines.md @@ -0,0 +1,206 @@ +--- +slug: developer-guide/coding-guidelines/c-guidelines +--- + +# C Guidelines + +This page collects the engineering conventions that keep cuVS C APIs stable, predictable, and easy to use from downstream projects and language bindings. Start with the [Contributor Guide](/developer-guide/contributing), then use this page when designing public C APIs, C wrappers, or C-facing documentation. + +## Local Development + +Most C API changes can be developed directly in this repository. Cross-project work may also require a local RAFT build or a downstream project that consumes the installed cuVS C headers and shared libraries. + +If source builds are not being used, install the local cuVS C artifacts into the consuming project's environment before testing the downstream change. + +## Public Interface + +### General Guidelines + +Public C APIs should be thin, ABI-stable wrappers around cuVS implementation code. Keep C headers free of C++ types, templates, namespaces, exceptions, and RAII-only ownership patterns. + +Expose only C-compatible types: + +1. Opaque handles for resources, indexes, models, and parameter objects. +2. Plain C structs for lightweight metadata and simple value groups. +3. `cuvsError_t` return values for API status. +4. Explicit pointer outputs for objects created by the API. + +Prefer explicit create and destroy functions for every opaque object that owns memory or other resources. + +### API Stability + +The C API is the stable boundary used by downstream integrations and cuVS language bindings. Add new functions or fields before removing old ones, avoid changing the meaning of existing parameters, and keep [ABI compatibility](../developer_guide/abi_stability.md) in mind when changing public structs or exported symbols. + +### Stateless C APIs + +Prefer stateless functions that take all required state explicitly: + +```c +cuvsError_t cuvsIvfPqBuild(cuvsResources_t res, + cuvsIvfPqIndexParams_t params, + DLManagedTensor* dataset, + cuvsIvfPqIndex_t index); + +cuvsError_t cuvsIvfPqSearch(cuvsResources_t res, + cuvsIvfPqSearchParams_t params, + cuvsIvfPqIndex_t index, + DLManagedTensor* queries, + DLManagedTensor* neighbors, + DLManagedTensor* distances); +``` + +Avoid APIs that hide global state, allocate persistent internal state without an owning handle, or require callers to understand C++ object lifetimes. + +### Functions On State + +When a C API creates an index, model, resource, or parameter object, expose matching operations for lifecycle and persistence in the same API family: + +```c +cuvsError_t cuvsIvfPqIndexCreate(cuvsIvfPqIndex_t* index); +cuvsError_t cuvsIvfPqIndexDestroy(cuvsIvfPqIndex_t index); + +cuvsError_t cuvsIvfPqSerialize(cuvsResources_t res, + const char* filename, + cuvsIvfPqIndex_t index); + +cuvsError_t cuvsIvfPqDeserialize(cuvsResources_t res, + const char* filename, + cuvsIvfPqIndex_t index); +``` + +## Common Design Considerations + +1. Use `.h` for public C headers and keep them consumable from both C and C++. +2. Wrap declarations with `extern "C"` guards when a header can be included from C++. +3. Mark exported public functions with `CUVS_EXPORT`. +4. Keep ownership explicit: the API that creates an object should document the matching destroy function. +5. Use DLPack tensors for array inputs and outputs where possible so callers can pass data across language and framework boundaries. + +### Performance + +Keep C wrappers thin. Validate inputs and translate handles at the boundary, but leave expensive work in the underlying cuVS implementation. + +Avoid hidden host-device copies and hidden synchronization. If a wrapper needs to synchronize, document that behavior clearly. + +### Threading Model + +C APIs should be safe to call from multiple host threads when each thread uses its own `cuvsResources_t` instance. Treat `cuvsResources_t` as the boundary for streams, memory resources, communication handles, and library handles. + +Avoid mutable process-wide state in C wrappers. If shared state is unavoidable, make ownership and synchronization explicit. + +### Asynchronous Operations And Stream Ordering + +C APIs should preserve the stream-ordering behavior of the underlying cuVS implementation. Do not add hidden synchronization only to simplify wrapper code. + +When a C function accepts `cuvsResources_t`, use the stream and resources associated with that handle. Work queued by the caller before the API should complete before internal work starts, and work queued by the caller after the API returns should wait for internal work that affects the result. + +### Resource Management + +Every successful create call that returns an owning handle should have a matching destroy call in examples and tests: + +```c +cuvsResources_t res; +cuvsIvfPqIndexParams_t params; +cuvsIvfPqIndex_t index; + +cuvsResourcesCreate(&res); +cuvsIvfPqIndexParamsCreate(¶ms); +cuvsIvfPqIndexCreate(&index); + +/* Use res, params, and index. */ + +cuvsIvfPqIndexDestroy(index); +cuvsIvfPqIndexParamsDestroy(params); +cuvsResourcesDestroy(res); +``` + +Destroy functions should tolerate cleanup after partial setup when practical, and examples should release resources in the reverse order they were acquired. + +### Multi-GPU + +Multi-GPU C APIs generally use one of two execution strategies: + +1. Single-process multi-GPU: one host process owns and coordinates multiple GPUs. Use `cuvsMultiGpuResourcesCreate` or `cuvsMultiGpuResourcesCreateWithDeviceIds` for this model. These functions return a `cuvsResources_t` backed by `raft::device_resources_snmg`; release it with `cuvsMultiGpuResourcesDestroy`. +2. One-process-per-GPU: each process owns one GPU and participates as a communication rank. APIs that wrap this model should accept the process-local `cuvsResources_t` for the calling rank and document how communicator setup, rank ownership, and synchronization are provided by the underlying implementation. + +APIs may support either strategy or both, but they should document which resource handle users are expected to create. Use `cuvsMultiGpuResourcesSetMemoryPool` to configure an RMM memory pool across devices managed by a single-process multi-GPU resource. Continue to use `cuvsStreamSet`, `cuvsStreamGet`, and `cuvsStreamSync` for stream ownership and synchronization through the supplied opaque resource handle. + +Single-GPU C APIs should not require communication libraries or multi-GPU setup. + +### Using Just-in-Time Link-Time Optimization + +C APIs may call implementations that use JIT link-time optimization, but the C wrapper should not duplicate JIT LTO policy or expose C++ implementation details. Keep runtime behavior documented at the API level when JIT compilation can affect first-call latency or cache behavior. + +For runtime and cache behavior, see [JIT Compilation](jit_compilation.md). For implementation guidance, see [Link-time Optimization](jit_lto_guide.md). + +## Coding Style + +### Formatting + +cuVS uses [pre-commit](https://pre-commit.com/) to run formatting, linting, spelling, and copyright checks. Install it with conda: + +```bash +conda install -c conda-forge pre-commit +``` + +Run checks before committing: + +```bash +pre-commit run +``` + +Run the full suite across the repository when needed: + +```bash +pre-commit run --all-files +``` + +You can also install the git hook: + +```bash +pre-commit install +``` + +### Core Hooks + +C headers and C wrapper implementation files are checked by the same formatting, spelling, Doxygen, and copyright hooks used by the rest of cuVS. + +Run Doxygen checks for public C API documentation: + +```bash +./ci/checks/doxygen.sh +``` + +[codespell](https://github.com/codespell-project/codespell) catches spelling issues. To apply suggested fixes interactively, run: + +```bash +codespell -i 3 -w . +``` + +### Include Style + +Use `#include ` for public cuVS C headers. Keep public C headers minimal and avoid including private C++ implementation headers from the public C interface. + +### Copyright + +RAPIDS pre-commit hooks check copyright headers on modified tracked files. To run that check manually: + +```bash +pre-commit run -a verify-copyright +``` + +## Code Quality + +### Testing + +Public C APIs need direct test coverage because downstream projects and language bindings rely on their runtime and ABI behavior. Prefer tests that exercise public entry points, lifecycle functions, error paths, and resource cleanup. + +### Error Handling + +C APIs should return `cuvsError_t` and should not let C++ exceptions cross the C boundary. Translate implementation failures into C error values and make sure callers can retrieve useful diagnostic information when available. + +Destroy functions should avoid throwing or failing in ways that make cleanup unsafe. + +### Documentation + +Public C APIs require user-facing Doxygen documentation. Document the purpose, parameters, return values, ownership rules, matching destroy functions, and any constraints that affect correct use. diff --git a/fern/pages/cluster/index.md b/fern/pages/cluster/index.md new file mode 100644 index 0000000000..7acded4879 --- /dev/null +++ b/fern/pages/cluster/index.md @@ -0,0 +1,11 @@ +--- +slug: user-guide/api-guides/clustering-guide +--- + +# Clustering Guide + +Use these guides for cuVS clustering APIs that group related vectors or build graph structures from pairwise relationships. + +- [K-Means](kmeans.md): partition vectors into a fixed number of clusters, often for scalable vector-search partitioning. +- [Single-linkage](single_linkage.md): build hierarchical clusters from nearest-neighbor relationships. +- [Spectral Clustering](spectral.md): use graph structure and spectral methods to find clusters with more complex shapes. diff --git a/fern/pages/cluster/kmeans.md b/fern/pages/cluster/kmeans.md new file mode 100644 index 0000000000..ffa2d40bb1 --- /dev/null +++ b/fern/pages/cluster/kmeans.md @@ -0,0 +1,453 @@ +# K-Means + +K-Means is a GPU-accelerated clustering algorithm. It groups rows into `n_clusters` groups by learning one centroid for each group, then assigning every row to the closest centroid. + +Use K-Means when you want to summarize a dataset with representative centers, assign vectors to coarse groups, build vector quantizers, or partition data before another algorithm. Unlike an ANN index, K-Means does not build a search structure for nearest-neighbor lookup. Its primary outputs are centroids, labels, inertia, and the number of training iterations. + +## Example API Usage + +[C API](/api-reference/c-api-cluster-kmeans) | [C++ API](/api-reference/cpp-api-cluster-kmeans) | [Python API](/api-reference/python-api-cluster-kmeans) | [Rust API](/api-reference/rust-api-cuvs-cluster-kmeans) + +### Fitting clusters + +Fitting learns the cluster centroids from a dataset. The input data can be on the device, and C, C++, and Python also support host-data paths that stream batches to the GPU. + + + + +```c +#include +#include + +cuvsResources_t res; +cuvsKMeansParams_t params; +DLManagedTensor *dataset; +DLManagedTensor *centroids; +double inertia; +int n_iter; + +load_dataset(dataset); +allocate_centroids(centroids); + +cuvsResourcesCreate(&res); +cuvsKMeansParamsCreate(¶ms); + +params->n_clusters = 1024; +params->max_iter = 300; +params->tol = 1e-4; + +cuvsKMeansFit(res, params, dataset, NULL, centroids, &inertia, &n_iter); + +cuvsKMeansParamsDestroy(params); +cuvsResourcesDestroy(res); +``` + + + + +```cpp +#include + +#include +#include + +#include + +using namespace cuvs::cluster; + +raft::device_resources res; +raft::device_matrix_view dataset = load_dataset(); +auto centroids = raft::make_device_matrix(res, 1024, dataset.extent(1)); + +kmeans::params params; +params.n_clusters = 1024; +params.max_iter = 300; +params.tol = 1e-4; + +float inertia; +int n_iter; + +kmeans::fit(res, + params, + dataset, + std::nullopt, + centroids.view(), + raft::make_host_scalar_view(&inertia), + raft::make_host_scalar_view(&n_iter)); +``` + + + + +```python +import cupy as cp + +from cuvs.cluster.kmeans import KMeansParams, fit + +dataset = cp.asarray(load_dataset(), dtype=cp.float32) +params = KMeansParams(n_clusters=1024, max_iter=300, tol=1e-4) + +centroids, inertia, n_iter = fit(params, dataset) +``` + + + + +```rust +use cuvs::cluster::kmeans::{self, Params}; +use cuvs::{ManagedTensor, Resources, Result}; + +fn fit_kmeans(dataset: &ndarray::Array2, n_clusters: usize) -> Result<()> { + let res = Resources::new()?; + let dataset = ManagedTensor::from(dataset).to_device(&res)?; + + let n_features = dataset.shape()[1]; + let centroids_host = ndarray::Array::::zeros((n_clusters, n_features)); + let mut centroids = ManagedTensor::from(¢roids_host).to_device(&res)?; + + let params = Params::new()? + .set_n_clusters(n_clusters as i32) + .set_max_iter(300) + .set_tol(1e-4); + + let (_inertia, _n_iter) = kmeans::fit(&res, ¶ms, &dataset, &None, &mut centroids)?; + Ok(()) +} +``` + + + + +### Assigning labels + +Prediction assigns each row to the nearest learned centroid. Use it after fitting when you need a cluster label per row. + + + + +```c +#include + +cuvsResources_t res; +cuvsKMeansParams_t params; +DLManagedTensor *dataset; +DLManagedTensor *centroids; +DLManagedTensor *labels; +double inertia; + +load_dataset(dataset); +load_centroids(centroids); +allocate_labels(labels); + +cuvsResourcesCreate(&res); +cuvsKMeansParamsCreate(¶ms); + +params->n_clusters = 1024; + +cuvsKMeansPredict(res, params, dataset, NULL, centroids, labels, true, &inertia); + +cuvsKMeansParamsDestroy(params); +cuvsResourcesDestroy(res); +``` + + + + +```cpp +#include + +#include +#include + +#include + +using namespace cuvs::cluster; + +raft::device_resources res; +raft::device_matrix_view dataset = load_dataset(); +raft::device_matrix_view centroids = load_centroids(); +auto labels = raft::make_device_vector(res, dataset.extent(0)); + +kmeans::params params; +params.n_clusters = centroids.extent(0); + +float inertia; + +kmeans::predict(res, + params, + dataset, + std::nullopt, + centroids, + labels.view(), + true, + raft::make_host_scalar_view(&inertia)); +``` + + + + +```python +from cuvs.cluster.kmeans import KMeansParams, fit, predict + +params = KMeansParams(n_clusters=1024) +centroids, _, _ = fit(params, dataset) + +labels, inertia = predict(params, dataset, centroids) +``` + + + + +```rust +use cuvs::cluster::kmeans::{self, Params}; +use cuvs::{ManagedTensor, Resources, Result}; + +fn predict_kmeans( + res: &Resources, + params: &Params, + dataset: &ManagedTensor, + centroids: &ManagedTensor, + n_samples: usize, +) -> Result<()> { + let labels_host = ndarray::Array::::zeros((n_samples,)); + let mut labels = ManagedTensor::from(&labels_host).to_device(res)?; + + let _inertia = + kmeans::predict(res, params, dataset, &None, centroids, &mut labels, true)?; + Ok(()) +} +``` + + + + +### Evaluating centroids + +The cluster cost, also called inertia, is the sum of squared distances from each row to its closest centroid. Use it to compare different runs or to check whether additional iterations meaningfully improve the clustering. + + + + +```c +double cost; +cuvsKMeansClusterCost(res, dataset, centroids, &cost); +``` + + + + +```cpp +float cost; +kmeans::cluster_cost(res, + dataset, + centroids, + raft::make_host_scalar_view(&cost)); +``` + + + + +```python +from cuvs.cluster.kmeans import cluster_cost + +inertia = cluster_cost(dataset, centroids) +``` + + + + +```rust +let inertia = kmeans::cluster_cost(&res, &dataset, ¢roids)?; +``` + + + + +## How K-Means works + +K-Means alternates between two steps: + +1. Assign each row to the closest centroid. +2. Move each centroid to the average of the rows assigned to it. + +The algorithm repeats those steps until it reaches `max_iter` or the inertia changes by less than `tol`. The GPU is useful because the expensive part is repeatedly comparing many rows against many centroids. + +## When to use K-Means + +Use K-Means when you need compact representatives for a dataset, cluster labels for downstream analysis, coarse partitions for batching or indexing, or vector quantization codebooks. + +K-Means works best when clusters are roughly spherical under the selected distance metric. If the data has complex shapes, very uneven cluster sizes, or strong outliers, consider using K-Means as a fast preprocessing step rather than treating the labels as final ground truth. + +## Standard and balanced K-Means + +Standard K-Means minimizes inertia. It can produce uneven cluster sizes if the data distribution is uneven. + +Balanced K-Means encourages more even cluster sizes. It is useful when clusters will be used as partitions for later work and very large clusters would create load imbalance. In cuVS, balanced K-Means is exposed through `balanced_params` in C++ and through `hierarchical=True` in C and Python. + +## Configuration parameters + +### Fit parameters + +| Parameter | Default | Description | +| --- | --- | --- | +| `metric` | `L2Expanded` / language default | Distance metric used to compare rows and centroids. Standard K-Means commonly uses squared L2 distance. | +| `n_clusters` | `8` | Number of clusters and output centroids. Larger values create finer groups but increase work and centroid memory. | +| `init` / `init_method` | `KMeansPlusPlus` | Initialization strategy. Use k-means++ for robust default seeding, random for faster but less stable seeding, or array initialization when providing centroids. | +| `max_iter` | `300` | Maximum number of training iterations for one run. | +| `tol` | `1e-4` | Relative inertia tolerance used for convergence. | +| `n_init` | `1` | Number of independent runs with different seeds. More runs can improve quality but multiply build time. | +| `oversampling_factor` | `2.0` | Oversampling factor used by k-means parallel initialization. | +| `batch_samples` | `32768` | Number of samples per tile for the nearest-centroid computation. Lower values reduce temporary memory. | +| `batch_centroids` | `0` | Number of centroids per tile. `0` means all centroids. Lower values reduce temporary memory. | +| `init_size` | `0` | Number of rows sampled for k-means++ initialization on host-data paths. `0` uses the default heuristic. | +| `streaming_batch_size` | `0` | Number of host rows streamed to the GPU per batch. `0` processes all host rows at once. | +| `hierarchical` | `false` | Enables hierarchical, balanced K-Means in C and Python. | +| `hierarchical_n_iters` | implementation default | Number of training iterations for hierarchical K-Means. | + +## Tuning + +Start with `n_clusters`. More clusters reduce average within-cluster distance, but they increase memory and the work per iteration. If clusters become too small or unstable, reduce `n_clusters` or increase the amount of data used for fitting. + +Use `KMeansPlusPlus` initialization for most workloads. Increase `n_init` when quality matters more than fit time, especially when different random seeds produce noticeably different inertia. + +Tune `max_iter` and `tol` together. If `n_iter` often reaches `max_iter`, increase `max_iter` or relax `tol`. If inertia stops improving early, lowering `max_iter` can reduce runtime. + +Use `batch_samples` and `batch_centroids` to control device memory for device-resident data. Smaller tiles reduce temporary memory but add more tiled work. + +Use `streaming_batch_size` when fitting host-resident datasets that do not fit on the GPU. Smaller batches reduce GPU memory pressure, while larger batches reduce transfer and launch overhead. + +Use balanced K-Means when cluster size matters. This is often useful when clusters are later used as work partitions, batches, or coarse groups for another algorithm. + +## Memory footprint + +K-Means memory is dominated by the input data, the centroid matrix, optional labels or weights, and temporary tiles used to compare samples with centroids. The exact scratch space depends on the selected data type and implementation path, but the estimates below are useful for planning. + +Variables: + +- `N`: Number of rows, or samples. +- `D`: Number of features per row. +- `K`: Number of clusters, or centroids. +- `S`: Number of samples processed in one GPU batch. +- `T_s`: Sample tile size, controlled by `batch_samples`. +- `T_c`: Centroid tile size, controlled by `batch_centroids`; if `batch_centroids = 0`, use `K`. +- `B_x`: Bytes per input element. +- `B_c`: Bytes per centroid element. +- `B_l`: Bytes per output label. + +### Scratch and maximum rows + +The `scratch` term covers temporary buffers that are not part of the persistent inputs or outputs: reduction buffers, assignment buffers, allocator padding, CUDA library workspaces, and memory held by the active memory resource. For a first capacity estimate, reserve a scratch headroom factor `H`. Use `H = 0.20` for K-Means fit and `H = 0.10` for prediction. If you can measure a representative run, use: + +$$ +H_{\text{measured}} + = + \frac{\text{observed\_peak} - \text{formula\_without\_scratch}} + {\text{formula\_without\_scratch}} +$$ + +Then set: + +$$ +M_{\text{usable}} + = (M_{\text{free}} - M_{\text{other}}) \cdot (1 - H) +$$ + +The capacity variables in this subsection are: + +- `M_free`: Free memory in the relevant memory space before the operation starts. Use device memory for GPU-resident formulas and host memory for formulas explicitly marked as host memory. +- `M_other`: Memory reserved for arrays, memory pools, concurrent work, or application buffers that are not included in the formula. +- `H`: Scratch headroom fraction reserved for temporary buffers and allocator overhead. +- `M_usable`: Memory budget left for the formula after subtracting `M_other` and reserving headroom. +- `observed_peak`: Peak memory observed during a smaller representative run. +- `formula_without_scratch`: Value of the selected peak formula with explicit `scratch` terms removed and without applying headroom. +- `peak_without_scratch(count)`: The selected peak formula rewritten as a function of the count being estimated, excluding scratch and headroom. The count is usually `N` for rows or vectors and `B` for K-selection batch rows. +- `B_per_row` / `B_per_vector`: Bytes added by one more row or vector in the selected formula. For linear formulas, add the coefficients of the count being estimated after fixed values such as `D`, `K`, `Q`, and `L` are substituted. +- `B_fixed`: Bytes in the selected formula that do not change with the estimated count, such as codebooks, centroids, fixed query batches, capped training buffers, or metadata. +- `N_max` / `B_max`: Estimated largest row, vector, or batch-row count that fits in `M_usable`. + + +To estimate the largest usable row count, rewrite the selected peak formula as: + +$$ +\text{peak\_without\_scratch}(N) + = N \cdot B_{\text{per\_row}} + B_{\text{fixed}} +$$ + +and solve: + +$$ +N_{\max} + = + \left\lfloor + \frac{M_{\text{usable}} - B_{\text{fixed}}} + {B_{\text{per\_row}}} + \right\rfloor +$$ + +For host streaming fit, solve for `S` first. `S` controls the active GPU batch size even when the full dataset has more than `S` rows. + +### Device-resident fit + +When the dataset is already on the GPU, the persistent data and centroids use: + +$$ +\begin{aligned} +\text{dataset\_size} &= N \cdot D \cdot B_x \\ +\text{centroids\_size} &= K \cdot D \cdot B_c +\end{aligned} +$$ + +The nearest-centroid computation is tiled. A useful estimate for the main distance tile is: + +$$ +\text{distance\_tile\_size} + \approx \min(N, T_s) \cdot \min(K, T_c) \cdot B_c +$$ + +The fit peak is approximately: + +$$ +\begin{aligned} +\text{fit\_peak} + \approx&\ \text{dataset\_size} + + \text{centroids\_size} \\ + &+ \text{distance\_tile\_size} + + \text{scratch} +\end{aligned} +$$ + +### Host streaming fit + +For host-resident data, cuVS can stream rows to the GPU in batches. If `streaming_batch_size = 0`, then `S = N`; otherwise `S = streaming_batch_size`. + +$$ +\begin{aligned} +\text{streaming\_batch\_size} + &= S \cdot D \cdot B_x \\ +\text{fit\_peak} + \approx&\ \text{streaming\_batch\_size} + + \text{centroids\_size} \\ + &+ \min(S, T_s) \cdot \min(K, T_c) \cdot B_c + + \text{scratch} +\end{aligned} +$$ + +Use a smaller `streaming_batch_size` when the host-data fit path runs out of GPU memory. Use a larger value when GPU memory is available and transfer overhead dominates. + +### Prediction + +Prediction needs the input rows, centroids, output labels, and a distance tile: + +$$ +\begin{aligned} +\text{labels\_size} &= N \cdot B_l \\ +\text{predict\_peak} + \approx&\ N \cdot D \cdot B_x + + K \cdot D \cdot B_c \\ + &+ \text{labels\_size} + + \text{distance\_tile\_size} + + \text{scratch} +\end{aligned} +$$ + +For large `K`, reduce `batch_centroids`. For large `N`, reduce `batch_samples` or use the host streaming fit path when fitting from host data. diff --git a/fern/pages/cluster/single_linkage.md b/fern/pages/cluster/single_linkage.md new file mode 100644 index 0000000000..1086bf22de --- /dev/null +++ b/fern/pages/cluster/single_linkage.md @@ -0,0 +1,223 @@ +# Single-linkage + +Single-linkage is a hierarchical clustering algorithm. It builds a tree of merges by repeatedly connecting the two closest clusters, where cluster distance is defined by the closest pair of points across the two clusters. + +Use single-linkage when you want a dendrogram, want to cut a hierarchy into a chosen number of clusters, or need clustering that can capture chain-like structure. Unlike K-Means, single-linkage does not learn centroids. + +## Example API Usage + +[C++ API](/api-reference/cpp-api-cluster-agglomerative) + +### Clustering data + +The C++ API can build labels directly from a dense row-major device matrix. The output dendrogram has `n_rows - 1` rows and two columns, and the labels vector has one label per input row. + + + + +```cpp +#include +#include + +#include +#include + +namespace agglomerative = cuvs::cluster::agglomerative; + +raft::device_resources res; +raft::device_matrix_view dataset = + load_dataset(); + +auto dendrogram = raft::make_device_matrix( + res, dataset.extent(0) - 1, 2); +auto labels = raft::make_device_vector(res, dataset.extent(0)); + +agglomerative::single_linkage(res, + dataset, + dendrogram.view(), + labels.view(), + cuvs::distance::DistanceType::L2Expanded, + 16, + agglomerative::Linkage::KNN_GRAPH, + 15); +``` + + + + +### Building a linkage + +Use the helper API when you need the minimum spanning tree, merge distances, or cluster sizes in addition to the dendrogram. + + + + +```cpp +#include + +namespace agglomerative = cuvs::cluster::agglomerative; +namespace linkage_params = agglomerative::helpers::linkage_graph_params; + +linkage_params::distance_params params; +params.dist_type = agglomerative::Linkage::KNN_GRAPH; +params.c = 15; + +agglomerative::helpers::build_linkage(res, + dataset, + params, + cuvs::distance::DistanceType::L2Expanded, + mst.view(), + dendrogram.view(), + distances.view(), + sizes.view(), + std::nullopt); +``` + + + + +## How Single-linkage works + +Single-linkage first builds a graph over the data and then finds a minimum spanning tree. Sorting the tree edges from shortest to longest gives the merge order for the dendrogram. Cutting that tree at the right number of components gives cluster labels. + +The `PAIRWISE` mode builds from pairwise distances. It is simple and fast for smaller datasets, but its memory grows quadratically. The `KNN_GRAPH` mode builds a sparse nearest-neighbor graph and can scale to much larger datasets, at the cost of more graph construction work. + +## When to use Single-linkage + +Use single-linkage when the hierarchy itself matters, when clusters may have elongated or connected shapes, or when you need a dendrogram for later analysis. + +Avoid single-linkage when small bridges between groups should not merge them. Because it uses the closest pair of points, it can chain through sparse connections that other clustering methods would separate. + +## Configuration parameters + +### Clustering parameters + +| Parameter | Default | Description | +| --- | --- | --- | +| `metric` | Required | Distance metric used to compare rows when constructing the graph. | +| `n_clusters` | Required | Number of clusters to assign after cutting the hierarchy. | +| `linkage` | `KNN_GRAPH` | Graph construction strategy. `PAIRWISE` uses more memory and can be faster for smaller datasets. `KNN_GRAPH` uses a sparse graph for larger datasets. | +| `c` | `15` | Constant used to choose the KNN graph size. Larger values add more graph edges and can improve connectivity, but increase memory and build time. | + +## Tuning + +Start with `KNN_GRAPH` for large datasets and `PAIRWISE` for smaller datasets where the pairwise distance matrix fits comfortably in memory. + +Increase `c` if the KNN graph is too sparse or produces unstable connectivity. Decrease it when memory use or graph construction time is too high. + +Choose the distance metric to match the data representation. The hierarchy can change substantially when the metric changes. + +## Memory footprint + +Single-linkage memory depends strongly on the graph construction mode. + +Variables: + +- `N`: Number of rows. +- `D`: Number of features per row. +- `k`: Number of neighbors used by the sparse graph. +- `B_x`: Bytes per input element. +- `B_d`: Bytes per distance value. +- `B_i`: Bytes per index value. + +### Scratch and maximum rows + +The formulas below show the large persistent arrays and graph buffers. `scratch` covers temporary graph-construction buffers, sort or merge workspace, allocator padding, CUDA library workspaces, and memory held by the active memory resource. For planning, reserve a headroom factor `H = 0.30` for single-linkage builds. If you can measure a representative smaller run, use: + +$$ +H_{\text{measured}} + = + \frac{\text{observed\_peak} - \text{formula\_without\_scratch}} + {\text{formula\_without\_scratch}} +$$ + +Then set: + +$$ +M_{\text{usable}} + = (M_{\text{free}} - M_{\text{other}}) \cdot (1 - H) +$$ + +The capacity variables in this subsection are: + +- `M_free`: Free memory in the relevant memory space before the operation starts. Use device memory for GPU-resident formulas and host memory for formulas explicitly marked as host memory. +- `M_other`: Memory reserved for arrays, memory pools, concurrent work, or application buffers that are not included in the formula. +- `H`: Scratch headroom fraction reserved for temporary buffers and allocator overhead. +- `M_usable`: Memory budget left for the formula after subtracting `M_other` and reserving headroom. +- `observed_peak`: Peak memory observed during a smaller representative run. +- `formula_without_scratch`: Value of the selected peak formula with explicit `scratch` terms removed and without applying headroom. +- `peak_without_scratch(count)`: The selected peak formula rewritten as a function of the count being estimated, excluding scratch and headroom. The count is usually `N` for rows or vectors and `B` for K-selection batch rows. +- `B_per_row` / `B_per_vector`: Bytes added by one more row or vector in the selected formula. For linear formulas, add the coefficients of the count being estimated after fixed values such as `D`, `K`, `Q`, and `L` are substituted. +- `B_fixed`: Bytes in the selected formula that do not change with the estimated count, such as codebooks, centroids, fixed query batches, capped training buffers, or metadata. +- `N_max` / `B_max`: Estimated largest row, vector, or batch-row count that fits in `M_usable`. + + +For KNN graph mode, substitute `k` and rewrite the peak as a linear function of `N`: + +$$ +\text{peak\_without\_scratch}(N) + = N \cdot B_{\text{per\_row}} + B_{\text{fixed}} +$$ + +Then estimate: + +$$ +N_{\max} + = + \left\lfloor + \frac{M_{\text{usable}} - B_{\text{fixed}}} + {B_{\text{per\_row}}} + \right\rfloor +$$ + +For pairwise mode, the dense distance matrix is quadratic. If both inputs have `N` rows, solve: + +$$ +N_{\max} + \approx + \left\lfloor + \sqrt{\frac{M_{\text{usable}} - B_{\text{fixed}}}{B_d}} + \right\rfloor +$$ + +### Pairwise mode + +The pairwise path can require a dense distance matrix: + +$$ +\text{pairwise\_distance\_size} + \approx N^2 \cdot B_d +$$ + +This mode is usually only practical when `N` is small enough for the quadratic matrix to fit comfortably. + +### KNN graph mode + +The sparse graph path stores roughly `N * k` weighted edges: + +$$ +\text{knn\_graph\_size} + \approx N \cdot k \cdot (B_d + 2B_i) +$$ + +The dendrogram and labels are smaller: + +$$ +\begin{aligned} +\text{dendrogram\_size} &\approx 2(N - 1) \cdot B_i \\ +\text{labels\_size} &= N \cdot B_i +\end{aligned} +$$ + +The sparse path peak is approximately: + +$$ +\begin{aligned} +\text{knn\_peak} + \approx&\ N \cdot D \cdot B_x + + \text{knn\_graph\_size} \\ + &+ \text{dendrogram\_size} + + \text{labels\_size} + + \text{scratch} +\end{aligned} +$$ diff --git a/fern/pages/cluster/spectral.md b/fern/pages/cluster/spectral.md new file mode 100644 index 0000000000..87f7b44fc7 --- /dev/null +++ b/fern/pages/cluster/spectral.md @@ -0,0 +1,219 @@ +# Spectral Clustering + +Spectral clustering groups data by first building a graph, then using eigenvectors of that graph to create a clustering-friendly embedding. It is useful when clusters are connected by graph structure rather than being compact around centroids. + +Use spectral clustering when the shape of the data is not well described by spherical clusters, or when you already have a meaningful connectivity graph. It is more expensive than K-Means, but it can separate clusters that K-Means would blend together. + +## Example API Usage + +[C++ API](/api-reference/cpp-api-cluster-spectral) + +### Clustering a dense dataset + +The dense-data overload builds a KNN connectivity graph internally, computes the spectral embedding, and assigns labels. + + + + +```cpp +#include + +#include +#include +#include + +namespace spectral = cuvs::cluster::spectral; + +raft::device_resources res; +raft::device_matrix_view dataset = load_dataset(); + +spectral::params params; +params.n_clusters = 8; +params.n_components = 8; +params.n_neighbors = 15; +params.n_init = 10; +params.tolerance = 1e-5f; +params.rng_state = raft::random::RngState{1234}; + +auto labels = raft::make_device_vector(res, dataset.extent(0)); + +spectral::fit_predict(res, params, dataset, labels.view()); +``` + + + + +### Clustering a connectivity graph + +Use the graph overload when the connectivity graph is already available or when you want to control graph construction separately. + + + + +```cpp +#include +#include + +namespace spectral = cuvs::cluster::spectral; +namespace embedding = cuvs::preprocessing::spectral_embedding; + +embedding::params graph_params; +graph_params.n_neighbors = 15; + +auto graph = raft::make_device_coo_matrix( + res, n_samples, n_samples, n_edges); + +embedding::helpers::create_connectivity_graph( + res, graph_params, dataset, graph.view()); + +auto labels = raft::make_device_vector(res, n_samples); + +spectral::fit_predict(res, params, graph.view(), labels.view()); +``` + + + + +## How Spectral Clustering works + +Spectral clustering builds a graph where nearby rows are connected. It then computes eigenvectors from that graph and uses those eigenvectors as a lower-dimensional embedding. K-Means is applied to the embedding to produce the final labels. + +This means spectral clustering depends on both graph quality and embedding quality. A good graph keeps points in the same natural group connected while avoiding too many edges between different groups. + +## When to use Spectral Clustering + +Use spectral clustering when clusters have curved, connected, or manifold-like structure that centroid methods struggle to capture. It is also useful when a domain-specific connectivity graph already exists. + +Avoid spectral clustering when a simple centroid model is enough. The graph and eigenvector computations add memory and runtime overhead compared with K-Means. + +## Configuration parameters + +### Fit parameters + +| Parameter | Default | Description | +| --- | --- | --- | +| `n_clusters` | Required | Number of output clusters. | +| `n_components` | Required | Number of eigenvectors used for the spectral embedding. This is usually equal to `n_clusters`. | +| `n_init` | Required | Number of K-Means initializations used when clustering the embedding. | +| `n_neighbors` | Required | Number of neighbors used when constructing the connectivity graph from dense data. | +| `tolerance` | Required | Tolerance for the eigenvalue solver. | +| `rng_state` | `0` | Random number generator state used for reproducible K-Means initialization. | + +## Tuning + +Start with `n_components = n_clusters`. Increase `n_components` only when extra embedding dimensions improve downstream clustering quality enough to justify the added work. + +Tune `n_neighbors` carefully. Too few neighbors can disconnect natural clusters; too many neighbors can blur the boundaries between clusters. + +Increase `n_init` when labels vary noticeably between runs. Lower it when runtime is more important and the embedding is stable. + +Use a stricter `tolerance` when the embedding quality is unstable. Relax it when eigensolver time dominates and clustering quality is already sufficient. + +## Memory footprint + +Spectral clustering memory is dominated by the input data, the connectivity graph, the spectral embedding, and K-Means scratch space on the embedding. + +Variables: + +- `N`: Number of rows. +- `D`: Number of features per row. +- `K`: Number of clusters. +- `C`: Number of spectral components. +- `M`: Number of graph edges. +- `B_x`: Bytes per input or embedding element. +- `B_w`: Bytes per graph edge weight. +- `B_i`: Bytes per index or label value. + +### Scratch and maximum rows + +The `scratch` term covers connectivity-graph construction workspace, Laplacian workspace, eigensolver workspace, K-Means workspace on the embedding, allocator padding, and memory held by the active memory resource. For a first estimate, reserve `H = 0.30` because graph and eigensolver workspace can be significant. If you can measure a representative smaller run, use: + +$$ +H_{\text{measured}} + = + \frac{\text{observed\_peak} - \text{formula\_without\_scratch}} + {\text{formula\_without\_scratch}} +$$ + +Then set: + +$$ +M_{\text{usable}} + = (M_{\text{free}} - M_{\text{other}}) \cdot (1 - H) +$$ + +The capacity variables in this subsection are: + +- `M_free`: Free memory in the relevant memory space before the operation starts. Use device memory for GPU-resident formulas and host memory for formulas explicitly marked as host memory. +- `M_other`: Memory reserved for arrays, memory pools, concurrent work, or application buffers that are not included in the formula. +- `H`: Scratch headroom fraction reserved for temporary buffers and allocator overhead. +- `M_usable`: Memory budget left for the formula after subtracting `M_other` and reserving headroom. +- `observed_peak`: Peak memory observed during a smaller representative run. +- `formula_without_scratch`: Value of the selected peak formula with explicit `scratch` terms removed and without applying headroom. +- `peak_without_scratch(count)`: The selected peak formula rewritten as a function of the count being estimated, excluding scratch and headroom. The count is usually `N` for rows or vectors and `B` for K-selection batch rows. +- `B_per_row` / `B_per_vector`: Bytes added by one more row or vector in the selected formula. For linear formulas, add the coefficients of the count being estimated after fixed values such as `D`, `K`, `Q`, and `L` are substituted. +- `B_fixed`: Bytes in the selected formula that do not change with the estimated count, such as codebooks, centroids, fixed query batches, capped training buffers, or metadata. +- `N_max` / `B_max`: Estimated largest row, vector, or batch-row count that fits in `M_usable`. + + +With dense input, substitute `M ≈ N * n_neighbors` into the graph formula. The peak then becomes approximately linear in `N`: + +$$ +\text{peak\_without\_scratch}(N) + = N \cdot B_{\text{per\_row}} + B_{\text{fixed}} +$$ + +Estimate the maximum row count with: + +$$ +N_{\max} + = + \left\lfloor + \frac{M_{\text{usable}} - B_{\text{fixed}}} + {B_{\text{per\_row}}} + \right\rfloor +$$ + +If the connectivity graph is precomputed, use its actual edge count `M` instead of `N * n_neighbors`. + +### Connectivity graph + +For dense-data clustering, the graph has roughly `N * n_neighbors` edges: + +$$ +M \approx N \cdot \text{n\_neighbors} +$$ + +The sparse COO graph size is approximately: + +$$ +\text{graph\_size} + \approx M \cdot (B_w + 2B_i) +$$ + +### Embedding and labels + +The spectral embedding and labels use: + +$$ +\begin{aligned} +\text{embedding\_size} &= N \cdot C \cdot B_x \\ +\text{labels\_size} &= N \cdot B_i +\end{aligned} +$$ + +The dense-data peak is approximately: + +$$ +\begin{aligned} +\text{fit\_peak} + \approx&\ N \cdot D \cdot B_x + + \text{graph\_size} \\ + &+ \text{embedding\_size} + + K \cdot C \cdot B_x + + \text{labels\_size} + + \text{scratch} +\end{aligned} +$$ + +For large `N`, reduce `n_neighbors` only if the graph remains connected enough for the clustering task. diff --git a/fern/pages/clustering.md b/fern/pages/clustering.md new file mode 100644 index 0000000000..aba4aa0092 --- /dev/null +++ b/fern/pages/clustering.md @@ -0,0 +1,83 @@ +# What is Clustering? + +Clustering groups similar vectors without requiring pre-labeled examples. Instead of asking for the nearest neighbors of one query, a clustering algorithm looks across a dataset and assigns vectors to groups that share some notion of similarity. + +Many clustering approaches use nearest-neighbor-style operations internally. For example, K-Means assigns each vector to its nearest centroid, which turns the assignment step into a nearest-neighbor search over the current set of centroids. + +Clustering is especially important for vectors because vectors do not have a natural lexical order. Text, relational, and other structured data can often be organized with lexicographic or key-based ordering. Vectors instead have geometric relationships: nearby points are similar, distant points are less similar, and useful organization depends on preserving spatial locality. Clustering provides that organization by grouping vectors that occupy nearby regions of the embedding space. + +In vector search systems, clustering is often used before search rather than after it. It can summarize data, find structure, create partitions, train quantizers, and make large datasets easier to index. The right clustering method depends on whether you need compact centroids, density-based regions, a hierarchy of connected components, or graph-aware groups. + +This page introduces the main clustering methods used around cuVS workflows: K-Means, single-linkage clustering, and spectral clustering. By the end, you should understand why K-Means is often the practical default for vector search at scale and when the other methods are a better fit. + +A four-panel overview comparing centroid-based, hierarchical, density-based, and graph-based clustering methods. + +## Clustering Algorithms in cuVS + +| Method | How it groups data | Good fit | Main tradeoff | +| --- | --- | --- | --- | +| [K-Means](cluster/kmeans.md) | Learns representative centroids and assigns each vector to the nearest centroid | Large-scale partitioning, vector quantization, summarization, and IVF-style workflows | Assumes clusters are reasonably compact around centroids | +| [Single-linkage](cluster/single_linkage.md) | Builds a hierarchy by repeatedly connecting the closest clusters | Dendrograms, connected components, and chain-like cluster structure | Can merge through thin bridges between groups | +| [Spectral clustering](cluster/spectral.md) | Builds a graph, embeds the graph with eigenvectors, then clusters the embedding | Curved, connected, or graph-shaped clusters | More expensive because it needs graph and eigensolver work | + +### K-Means + +K-Means learns `k` centroid vectors and assigns each data vector to the closest centroid. Each centroid acts like a representative for one group. The algorithm alternates between assigning vectors to centroids and updating centroids from the assigned vectors. + +K-Means is often preferred for vector search at scale because it produces compact, easy-to-use partitions. A centroid table is small compared with the full dataset, assigning a vector to the nearest centroid is straightforward, and the work maps well to GPUs. This makes K-Means a natural fit for coarse partitioning in IVF indexes, vector quantization, dataset summarization, and training workflows that need predictable memory behavior. + +The main limitation is shape. K-Means works best when clusters are roughly compact and centroid-like. If the natural groups are curved, chained, or defined by graph connectivity, K-Means may split one group or merge several groups that should stay separate. + +See the [K-Means](cluster/kmeans.md) guide for API examples and memory guidance. + +### Single-Linkage Clustering + +Single-linkage clustering is hierarchical. It starts with each vector as its own cluster, then repeatedly merges the two clusters connected by the shortest distance between any pair of points. The result is a tree of merges called a dendrogram. + +This makes single-linkage useful when the hierarchy itself matters or when clusters are connected by thin paths. It can capture chain-like structures that centroid methods may miss. In graph terms, single-linkage is closely related to building a minimum spanning tree and cutting it into connected components. + +The same behavior can also be a weakness. Because a single close pair can merge two clusters, single-linkage can chain through sparse bridges and combine groups that should remain separate. It is usually less natural than K-Means for balanced vector-search partitions, especially when the goal is fast assignment and predictable partition sizes. + +See the [Single-linkage](cluster/single_linkage.md) guide for API examples and tuning notes. + +### Spectral Clustering + +Spectral clustering builds a graph over the data, computes an embedding from that graph, and then clusters the embedding, often with K-Means. It uses connectivity rather than only direct distance to centroids. + +This is useful when the data has manifold-like structure: points in the same group may be connected through local neighborhoods even if the group is not compact in the original space. Spectral clustering can separate groups that K-Means would blend together. + +The tradeoff is cost. Spectral clustering needs graph construction and eigenvector computation before the final clustering step. That extra work can be worthwhile for exploratory analysis or graph-shaped data, but it is usually heavier than K-Means for large vector-search indexing pipelines. + +See the [Spectral Clustering](cluster/spectral.md) guide for API examples and configuration details. + +## Why K-Means is common in vector search + +Large vector search systems usually need partitions that are cheap to train, cheap to store, cheap to assign, and easy to probe at query time. K-Means is a good match for that shape of problem. + +In an IVF-style index, K-Means centroids define coarse partitions. During search, a query is compared with the centroids first, then only the most relevant partitions are searched. This turns one large search problem into a smaller search over selected partitions. It also makes quantization easier because each vector can be represented by a coarse centroid assignment plus optional residual information. + +K-Means is not always the best clustering algorithm in a statistical sense. It is often the best engineering compromise for vector search at scale because it gives a simple partitioning structure that supports fast indexing, fast query routing, GPU parallelism, and predictable memory use. + +## How the methods differ + +K-Means is centroid-based. It asks, "Which representative center is closest?" This makes it simple, scalable, and useful for partitioning. + +Single-linkage is hierarchy-based. It asks, "Which clusters are connected by the closest pair of points?" This makes it useful for dendrograms and connected structure, but sensitive to chaining. + +Spectral clustering is graph-based. It asks, "Which points are connected through the neighborhood graph?" This makes it powerful for non-spherical clusters, but more expensive than centroid-based clustering. + +## Choosing a starting point + +Use K-Means when you need scalable partitions, coarse quantization, representative centroids, or a simple baseline for large vector datasets. + +Use single-linkage when the merge tree matters, when clusters may be connected by paths, or when you need to analyze hierarchical structure. + +Use spectral clustering when local graph connectivity reveals structure that centroid distance alone does not capture. + +For vector search at scale, start with K-Means unless you have a clear reason to preserve hierarchy or graph connectivity. It is usually the easiest clustering method to connect to indexing, quantization, and query routing. + +## Conclusion + +Clustering helps turn an unstructured vector collection into groups that can be summarized, inspected, compressed, or searched more efficiently. K-Means, single-linkage, and spectral clustering all group nearby points, but they define "nearby" in different ways: centroids, closest links, and graph connectivity. + +For production vector search, K-Means is often the practical starting point because it creates simple partitions that scale well. Single-linkage and spectral clustering are valuable when the structure of the data is more important than creating fast, balanced search partitions. diff --git a/fern/pages/coding_guidelines.md b/fern/pages/coding_guidelines.md new file mode 100644 index 0000000000..13f314be44 --- /dev/null +++ b/fern/pages/coding_guidelines.md @@ -0,0 +1,14 @@ +--- +slug: developer-guide/coding-guidelines +--- + +# Coding Guidelines + +Use these pages when changing cuVS APIs, implementation code, bindings, packaging, or developer-facing documentation. They collect the conventions that keep cuVS predictable for contributors and downstream projects. + +## Language Guidelines + +- [C Guidelines](c_guidelines.md): design ABI-stable C APIs, manage opaque handles, and keep lifecycle, error handling, and documentation patterns consistent. +- [C++ Guidelines](cpp_guidelines.md): design public C++ APIs, manage CUDA resources, follow stateless API patterns, and write implementation code that fits cuVS conventions. +- [Java Guidelines](java_guidelines.md): update Java APIs, Panama bindings, native resource ownership, Maven packaging, and Java-facing documentation consistently. +- [Python Guidelines](python_guidelines.md): update Python APIs, Cython bindings, packaging, formatting, and Python-facing documentation consistently. diff --git a/fern/pages/comparing_indexes.md b/fern/pages/comparing_indexes.md new file mode 100644 index 0000000000..434cffbe27 --- /dev/null +++ b/fern/pages/comparing_indexes.md @@ -0,0 +1,58 @@ +# Methodologies + +Vector search indexes should be compared by both search quality and performance. A fast index is not useful if it misses too many neighbors, and a high-recall index may not be practical if it is too slow to build or query. For index selection guidance, see [Vector Database](vector_databases_vs_vector_search.md). + +This page describes how to make benchmark results comparable by using recall buckets, Pareto curves, and consistent reporting for build and search metrics. It also explains how these ideas apply to large datasets and points to cuVS Bench for reproducible benchmark runs. + +## Pareto curves + +Imagine every tuning run is a toy car. You want a car that is fast, but you also care how much work it took to build. If one car is both faster and easier to build than another car, the slower and harder-to-build car is not a useful choice. The cars that are not beaten this way form the Pareto curve. + +For vector indexes, each tuning run is a point with [quality](#recall), build time, and search performance. A point is on the Pareto curve when no other run is better on the metric being compared without making another metric worse. Finding these points usually requires a parameter sweep or another hyperparameter optimization method. + +Example Pareto curve for vector search tuning runs. Green points form the frontier where no other run has both higher quality and lower latency. + +For each quality bucket, summarize build time by taking the points on the Pareto curve in that bucket and averaging their corresponding build times. This gives an expected build time for the quality window instead of forcing one run to represent the whole bucket. + +## Recall + +Recall measures how many exact nearest neighbors were returned by an approximate search. For one query, recall is the number of returned neighbors that also appear in the exact ground-truth result, divided by `k`. Across many queries, divide the total number of matched neighbors by `n_queries * k`. + +Index parameters control the recall and performance trade-off. The figure below shows eight indexes trained on the same data with different parameters. Higher recall often requires longer build times or slower searches, so reporting only the fastest or highest-recall run is not a fair comparison. + +index recalls + +## Fair comparisons + +Compare latency, throughput, and build time only at similar recall levels. If two indexes are measured at different recall, the comparison mixes quality and speed into one number, and this is not a fair comparison. + +A practical approach is to group results into recall buckets: + +| Recall bucket | Typical use | +| --- | --- | +| 80% - 89% | Fast exploratory search | +| 90% - 94% | Lower-latency approximate search | +| 95% - 98% | High-quality approximate search | +| 99%+ | Near-exact search | + +recall buckets + +This makes results easier to interpret. For example: "At 95% recall, model A builds 3x faster than model B, but model B has 2x lower latency." + +build benchmarks + +## Large datasets + +For database architecture terms, see the [Vector Database](vector_databases_vs_vector_search.md) guide. This page focuses on how to benchmark once the evaluation scope is clear: a standalone index, one local partition, a globally partitioned index, or the full database system. + +Representative-sample tuning is appropriate when the benchmarked sample matches the unit that will actually be searched in production. For locally partitioned systems, that usually means tuning against the expected partition or segment size, not the full database size. For globally partitioned systems, tuning is more dependent on the full data distribution, so random samples need to be used carefully. + +For a step-by-step workflow, see [Tuning Indexes](tuning_guide.md). + +## Methodology summary + +- Define the scope, dataset, distance metric, `k`, batch size, filters, hardware, and concurrency before comparing results. +- Generate exact ground truth, sweep or tune build and search parameters, group results into recall buckets, and compare Pareto points within each bucket. +- Report recall, latency, throughput, build time, and memory (if needed) together so quality and performance are not separated from the cost of achieving them. + +cuVS provides [cuVS Bench](cuvs_bench/introduction.md) for reproducible benchmarks that follow these methodologies and produce comparable outputs across datasets, algorithms, and hardware. diff --git a/docs/source/contributing.md b/fern/pages/contributing.md similarity index 94% rename from docs/source/contributing.md rename to fern/pages/contributing.md index 1a58da4d75..7b3bd81fe3 100755 --- a/docs/source/contributing.md +++ b/fern/pages/contributing.md @@ -18,9 +18,10 @@ into three categories: - If you need more context on a particular issue, please ask and we shall provide. - ## Code contributions +Performance-critical changes require [proper benchmarks](cpp_guidelines.md#performance-benchmarking). Pull requests that affect performance-critical paths will not be merged until those benchmarks are produced; there are no exceptions to this rule. + ### Your first issue 1. Read the project's [README.md](https://github.com/rapidsai/cuvs) @@ -37,7 +38,6 @@ into three categories: Remember, if you are unsure about anything, don't hesitate to comment on issues and ask for clarifications! - ### Python / Pre-commit hooks CUVS uses [pre-commit](https://pre-commit.com/) to execute code linters and formatters such as @@ -73,7 +73,6 @@ Now code linters and formatters will be run each time you commit changes. You can skip these checks with `git commit --no-verify` or with the short version `git commit -n`. - ### Seasoned developers Once you have gotten your feet wet and are more comfortable with the code, you diff --git a/fern/pages/cpp_api/cpp-api-cluster-agglomerative.md b/fern/pages/cpp_api/cpp-api-cluster-agglomerative.md new file mode 100644 index 0000000000..dff159fb11 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-cluster-agglomerative.md @@ -0,0 +1,222 @@ +--- +slug: api-reference/cpp-api-cluster-agglomerative +--- + +# Agglomerative + +_Source header: `cuvs/cluster/agglomerative.hpp`_ + +## agglomerative clustering hyperparameters + + +### cluster::agglomerative::Linkage + +Determines the method for computing the minimum spanning tree (MST) + +```cpp +enum Linkage { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `PAIRWISE` | `0` | +| `KNN_GRAPH` | `1` | + +## Types + + +### cluster::agglomerative::single_linkage_output + +Simple container object for consolidating linkage results. This closely + +mirrors the trained instance variables populated in Scikit-learn's AgglomerativeClustering estimator. + +```cpp +template +class single_linkage_output { ... }; +``` + +## single-linkage clustering APIs + + +### cluster::agglomerative::single_linkage + +Single-linkage clustering, capable of constructing a KNN graph to + +```cpp +void single_linkage( +raft::resources const& handle, +raft::device_matrix_view X, +raft::device_matrix_view dendrogram, +raft::device_vector_view labels, +cuvs::distance::DistanceType metric, +size_t n_clusters, +cuvs::cluster::agglomerative::Linkage linkage = cuvs::cluster::agglomerative::Linkage::KNN_GRAPH, +std::optional c = std::make_optional(DEFAULT_CONST_C)); +``` + +scale the algorithm beyond the n^2 memory consumption of implementations that use the fully-connected graph of pairwise distances by connecting a knn graph when k is not large enough to connect it. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle | +| `X` | in | `raft::device_matrix_view` | dense input matrix in row-major layout | +| `dendrogram` | out | `raft::device_matrix_view` | output dendrogram (size [n_rows - 1] * 2) | +| `labels` | out | `raft::device_vector_view` | output labels vector (size n_rows) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance metric to use when constructing connectivities graph | +| `n_clusters` | in | `size_t` | number of clusters to assign data samples | +| `linkage` | in | [`cuvs::cluster::agglomerative::Linkage`](/api-reference/cpp-api-cluster-agglomerative#cluster-agglomerative-linkage) | strategy for constructing the linkage. PAIRWISE uses more memory but can be faster for smaller datasets. KNN_GRAPH allows the memory usage to be controlled (using parameter c) at the expense of potentially additional minimum spanning tree iterations. Default: `cuvs::cluster::agglomerative::Linkage::KNN_GRAPH`. | +| `c` | in | `std::optional` | a constant used when constructing linkage from knn graph. Allows the indirect control of k. The algorithm will set `k = log(n) + c` Default: `std::make_optional<int>(DEFAULT_CONST_C)`. | + +**Returns** + +`void` + + +### cluster::agglomerative::helpers::linkage_graph_params::distance_params + +Specialized parameters to build the KNN graph with regular distances + +```cpp +struct distance_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `c` | `int` | a constant used when constructing linkage from knn graph. Allows the indirect control of k. The algorithm will set `k = log(n) + c` | +| `dist_type` | [`cuvs::cluster::agglomerative::Linkage`](/api-reference/cpp-api-cluster-agglomerative#cluster-agglomerative-linkage) | strategy for constructing the linkage. PAIRWISE uses more memory but can be faster for smaller datasets. KNN_GRAPH allows the memory usage to be controlled (using parameter c) | + + +### cluster::agglomerative::helpers::linkage_graph_params::mutual_reachability_params + +Specialized parameters to build the Mutual Reachability graph + +```cpp +struct mutual_reachability_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `min_samples` | `int` | this neighborhood will be selected for core distances. | +| `alpha` | `float` | weight applied when internal distance is chosen for mutual reachability (value of 1.0 disables the weighting) | +| `brute_force_params` | [`cuvs::neighbors::all_neighbors::all_neighbors_params all_neighbors_params{ cuvs::neighbors::graph_build_params::`](/api-reference/cpp-api-neighbors-all-neighbors#neighbors-all-neighbors-all-neighbors-params) | Parameters for building the mutual reachability graph using an underlying KNN algorithm. The all-neighbors graph construction algorithm enables building the mutual reachability graph on datasets larger than device memory by:
1. Partitioning the dataset into overlapping clusters,
2. Computing local KNN graphs within each cluster, and
3. Merging the local graphs into a single global graph. Key fields:
- graph_build_params: Selects the KNN construction method (Brute Force or NN Descent) and controls algorithm-specific parameters.
- n_clusters: Number of partitions (batches) to split the data into. Larger `n_clusters` reduces memory usage but may reduce accuracy if `overlap_factor` is too low. Recommended starting value: `n_clusters = 4`. Increase progressively (4 → 8 → 16 ...) to reduce memory usage at the cost of some accuracy. This is independent of `overlap_factor` as long as `overlap_factor < n_clusters`.
- overlap_factor: Number of nearest clusters each data point is assigned to. Higher `overlap_factor` improves accuracy at the cost of memory and performance. Recommended starting value: `overlap_factor = 2`. Increase gradually (2 → 3 → 4 ...) for better accuracy with higher device memory usage.
- metric: Distance metric to use when computing nearest neighbors. | + + +### cluster::agglomerative::helpers::build_linkage + +Given a dataset, builds the KNN graph, connects graph components and builds a linkage + +```cpp +void build_linkage( +raft::resources const& handle, +raft::device_matrix_view X, +std::variant linkage_graph_params, +cuvs::distance::DistanceType metric, +raft::device_coo_matrix_view out_mst, +raft::device_matrix_view dendrogram, +raft::device_vector_view out_distances, +raft::device_vector_view out_sizes, +std::optional> core_dists); +``` + +(dendrogram). Returns the Minimum Spanning Tree edges sorted by weight and the dendrogram. Reachability space + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for resource reuse | +| `X` | in | `raft::device_matrix_view` | data points on device memory (size n_rows * d) | +| `linkage_graph_params` | in | [`std::variant`](/api-reference/cpp-api-cluster-agglomerative#cluster-agglomerative-helpers-linkage-graph-params-mutual-reachability-params) | Parameters controlling how the KNN graph is built. This can be either:
- distance_params: standard distance-based KNN graph construction for traditional agglomerative clustering.
- mutual_reachability_params: parameters to compute a mutual reachability graph for density-aware hierarchical clustering (e.g. HDBSCAN). | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance metric to use | +| `out_mst` | out | `raft::device_coo_matrix_view` | output MST sorted by edge weights (size n_rows - 1) | +| `dendrogram` | out | `raft::device_matrix_view` | output dendrogram (size [n_rows - 1] * 2) | +| `out_distances` | out | `raft::device_vector_view` | distances for output | +| `out_sizes` | out | `raft::device_vector_view` | cluster sizes of output | +| `core_dists` | out | `std::optional>` | (optional) core distances (size m). Must be supplied in the Mutual | + +**Returns** + +`void` + +**Additional overload:** `cluster::agglomerative::helpers::build_linkage` + +Given a dataset, builds the KNN graph, connects graph components and builds a linkage + +```cpp +void build_linkage( +raft::resources const& handle, +raft::host_matrix_view X, +std::variant linkage_graph_params, +cuvs::distance::DistanceType metric, +raft::device_coo_matrix_view out_mst, +raft::device_matrix_view dendrogram, +raft::device_vector_view out_distances, +raft::device_vector_view out_sizes, +std::optional> core_dists); +``` + +(dendrogram). Returns the Minimum Spanning Tree edges sorted by weight and the dendrogram. Reachability space + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for resource reuse | +| `X` | in | `raft::host_matrix_view` | data points on host memory (size n_rows * d) | +| `linkage_graph_params` | in | [`std::variant`](/api-reference/cpp-api-cluster-agglomerative#cluster-agglomerative-helpers-linkage-graph-params-mutual-reachability-params) | Parameters controlling how the KNN graph is built. This can be either:
- distance_params: standard distance-based KNN graph construction for traditional agglomerative clustering.
- mutual_reachability_params: parameters to compute a mutual reachability graph for density-aware hierarchical clustering (e.g. HDBSCAN). | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance metric to use | +| `out_mst` | out | `raft::device_coo_matrix_view` | output MST sorted by edge weights (size n_rows - 1) | +| `dendrogram` | out | `raft::device_matrix_view` | output dendrogram (size [n_rows - 1] * 2) | +| `out_distances` | out | `raft::device_vector_view` | distances for output | +| `out_sizes` | out | `raft::device_vector_view` | cluster sizes of output | +| `core_dists` | out | `std::optional>` | (optional) core distances (size m). Must be supplied in the Mutual | + +**Returns** + +`void` + + +### cluster::agglomerative::helpers::build_dendrogram + +Build dendrogram from a Minimum Spanning Tree (MST). + +```cpp +void build_dendrogram(raft::resources const& handle, +raft::device_vector_view rows, +raft::device_vector_view cols, +raft::device_vector_view data, +raft::device_matrix_view children, +raft::device_vector_view out_delta, +raft::device_vector_view out_size); +``` + +This function takes a sorted MST (represented as edges with source, destination, and weights) and constructs a dendrogram (hierarchical clustering tree) on the host. + +nnz) + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft resources handle | +| `rows` | in | `raft::device_vector_view` | Source nodes of the MST edges (device memory, size: nnz) | +| `cols` | in | `raft::device_vector_view` | Destination nodes of the MST edges (device memory, size: nnz) | +| `data` | in | `raft::device_vector_view` | Edge weights/distances of the MST (device memory, size: nnz) | +| `children` | out | `raft::device_matrix_view` | Output dendrogram children array (device memory, size: nnz * 2) Each pair of consecutive elements represents the two children merged at each step of the hierarchy | +| `out_delta` | out | `raft::device_vector_view` | Output distances/heights at which clusters are merged (device memory, size: | +| `out_size` | out | `raft::device_vector_view` | Output cluster sizes at each merge step (device memory, size: nnz) | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-cluster-kmeans.md b/fern/pages/cpp_api/cpp-api-cluster-kmeans.md new file mode 100644 index 0000000000..0979c1bb0f --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-cluster-kmeans.md @@ -0,0 +1,1100 @@ +--- +slug: api-reference/cpp-api-cluster-kmeans +--- + +# K-Means + +_Source header: `cuvs/cluster/kmeans.hpp`_ + +## Types + + +### cluster::kmeans::base_params + +Base structure for parameters that are common to all k-means algorithms + +```cpp +struct base_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | Metric to use for distance computation. The supported metrics can vary per algorithm. | + +## k-means hyperparameters + + +### cluster::kmeans::params + +Simple object to specify hyper-parameters to the kmeans algorithm. + +```cpp +struct params : base_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_clusters` | `int` | The number of clusters to form as well as the number of centroids to generate (default:8). | +| `init` | `InitMethod` | Method for initialization, defaults to k-means++:
- InitMethod::KMeansPlusPlus (k-means++): Use scalable k-means++ algorithm to select the initial cluster centers.
- InitMethod::Random (random): Choose 'n_clusters' observations (rows) at random from the input data for the initial centroids.
- InitMethod::Array (ndarray): Use 'centroids' as initial cluster centers. | +| `max_iter` | `int` | Maximum number of iterations of the k-means algorithm for a single run. | +| `tol` | `double` | Relative tolerance with regards to inertia to declare convergence. | +| `verbosity` | `rapids_logger::level_enum` | verbosity level. | +| `rng_state` | `raft::random::RngState` | Seed to the random number generator. | +| `n_init` | `int` | Number of instance k-means algorithm will be run with different seeds. | +| `oversampling_factor` | `double` | Oversampling factor for use in the k-means\|\| algorithm | +| `batch_samples` | `int` | batch_samples and batch_centroids are used to tile 1NN computation which is useful to optimize/control the memory footprint Default tile is [batch_samples x n_clusters] i.e. when batch_centroids is 0 then don't tile the centroids NB: These parameters are unrelated to streaming_batch_size, which controls how many samples to transfer from host to device per batch when processing out-of-core data. | +| `batch_centroids` | `int` | if 0 then batch_centroids = n_clusters | +| `init_size` | `int64_t` | Number of samples to randomly draw for the KMeansPlusPlus initialization step. A random subset of this size is used for centroid seeding. Only applies when dataset is on host; for device data the full dataset is always used for seeding and this parameter is ignored. When set to 0 (default) with host data uses `min(3 * n_clusters, n_samples)` as a default. Default: 0. | +| `streaming_batch_size` | `int64_t` | Number of samples to process per GPU batch when fitting with host data. When set to 0, defaults to n_samples (process all at once). Only used by the batched (host-data) code path and ignored by device-data overloads. Default: 0 (process all data at once). | + + +### cluster::kmeans::balanced_params + +Simple object to specify hyper-parameters to the balanced k-means algorithm. + +The following metrics are currently supported in k-means balanced: + +- CosineExpanded +- InnerProduct +- L2Expanded +- L2SqrtExpanded + +```cpp +struct balanced_params : base_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_iters` | `uint32_t` | Number of training iterations | + + +### cluster::kmeans::kmeans_type + +Type of k-means algorithm. + +```cpp +enum class kmeans_type { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `KMeans` | `0` | +| `KMeansBalanced` | `1` | + +## k-means clustering APIs + + +### cluster::kmeans::fit + +Find clusters with k-means algorithm using batched processing of host data. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::host_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +TODO: Evaluate replacing the extent type with int64_t. Reference issue: https://github.com/rapidsai/cuvs/issues/1961 + +This overload supports out-of-core computation where the dataset resides on the host. Data is processed in GPU-sized batches, streaming from host to device. The batch size is controlled by params.streaming_batch_size. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. Batch size is read from params.streaming_batch_size. | +| `X` | in | `raft::host_matrix_view` | Training instances on HOST memory. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X (on host). [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm using batched processing of host data. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::host_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | | `raft::resources const&` | | +| `params` | | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | | +| `X` | | `raft::host_matrix_view` | | +| `sample_weight` | | `std::optional>` | | +| `centroids` | | `raft::device_matrix_view` | | +| `inertia` | | `raft::host_scalar_view` | | +| `n_iter` | | `raft::host_scalar_view` | | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find clusters with k-means algorithm. + +```cpp +void fit(raft::resources const& handle, +const cuvs::cluster::kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +Initial centroids are chosen with k-means++ algorithm. Empty clusters are reinitialized by choosing new centroids with k-means++ algorithm. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const cuvs::cluster::kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `raft::device_matrix_view` | [in] When init is InitMethod::Array, use centroids as the initial cluster centers. [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find balanced clusters with k-means algorithm. + +```cpp +void fit(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +std::optional> inertia = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | out | `raft::device_matrix_view` | [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `std::optional>` | Sum of squared distances of samples to their closest cluster center. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find balanced clusters with k-means algorithm. + +```cpp +void fit(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +std::optional> inertia = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | inout | `raft::device_matrix_view` | [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `std::optional>` | Sum of squared distances of samples to their closest cluster center. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find balanced clusters with k-means algorithm. + +```cpp +void fit(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +std::optional> inertia = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | inout | `raft::device_matrix_view` | [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `std::optional>` | Sum of squared distances of samples to their closest cluster center. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit` + +Find balanced clusters with k-means algorithm. + +```cpp +void fit(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +std::optional> inertia = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | inout | `raft::device_matrix_view` | [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `inertia` | out | `std::optional>` | Sum of squared distances of samples to their closest cluster center. Default: `std::nullopt`. | + +**Returns** + +`void` + + +### cluster::kmeans::predict + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::device_vector_view labels, +bool normalize_weight, +raft::host_scalar_view inertia); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::device_vector_view labels, +bool normalize_weight, +raft::host_scalar_view inertia); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::device_vector_view labels, +bool normalize_weight, +raft::host_scalar_view inertia); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +raft::device_matrix_view centroids, +raft::device_vector_view labels, +bool normalize_weight, +raft::host_scalar_view inertia); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `normalize_weight` | in | `bool` | True if the weights should be normalized | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::predict` + +Predict the closest cluster each sample in X belongs to. + +```cpp +void predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | New data to predict. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + + +### cluster::kmeans::fit_predict + +Compute k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +std::optional> centroids, +raft::device_vector_view labels, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `std::optional>` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit_predict` + +Compute k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +std::optional> centroids, +raft::device_vector_view labels, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `std::optional>` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit_predict` + +Compute k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +std::optional> centroids, +raft::device_vector_view labels, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `std::optional>` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit_predict` + +Compute k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +std::optional> sample_weight, +std::optional> centroids, +raft::device_vector_view labels, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `sample_weight` | in | `std::optional>` | Optional weights for each observation in X. [len = n_samples] | +| `centroids` | inout | `std::optional>` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | +| `inertia` | out | `raft::host_scalar_view` | Sum of squared distances of samples to their closest cluster center. | +| `n_iter` | out | `raft::host_scalar_view` | Number of iterations run. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit_predict` + +Compute balanced k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | inout | `raft::device_matrix_view` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::fit_predict` + +Compute balanced k-means clustering and predicts cluster index for each sample + +```cpp +void fit_predict(const raft::resources& handle, +cuvs::cluster::kmeans::balanced_params const& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_vector_view labels); +``` + +in the input. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle. | +| `params` | in | [`cuvs::cluster::kmeans::balanced_params const&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-balanced-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | inout | `raft::device_matrix_view` | Optional [in] When init is InitMethod::Array, use centroids as the initial cluster centers [out] The generated centroids from the kmeans algorithm are stored at the address pointed by 'centroids'. [dim = n_clusters x n_features] | +| `labels` | out | `raft::device_vector_view` | Index of the cluster each sample in X belongs to. [len = n_samples] | + +**Returns** + +`void` + + +### cluster::kmeans::transform + +Transform X to a cluster-distance space. + +```cpp +void transform(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_matrix_view X_new); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `X_new` | out | `raft::device_matrix_view` | X transformed in the new space. [dim = n_samples x n_features] | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::transform` + +Transform X to a cluster-distance space. + +```cpp +void transform(raft::resources const& handle, +const kmeans::params& params, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::device_matrix_view X_new); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | The raft handle. | +| `params` | in | [`const kmeans::params&`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-params) | Parameters for KMeans model. | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `X_new` | out | `raft::device_matrix_view` | X transformed in the new space. [dim = n_samples x n_features] | + +**Returns** + +`void` + + +### cluster::kmeans::cluster_cost + +Compute (optionally weighted) cluster cost + +```cpp +void cluster_cost( +const raft::resources& handle, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::host_scalar_view cost, +std::optional> sample_weight = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `cost` | out | `raft::host_scalar_view` | Resulting cluster cost | +| `sample_weight` | in | `std::optional>` | Optional per-sample weights. [len = n_samples] Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::cluster_cost` + +Compute cluster cost + +```cpp +void cluster_cost( +const raft::resources& handle, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::host_scalar_view cost, +std::optional> sample_weight = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `cost` | out | `raft::host_scalar_view` | Resulting cluster cost | +| `sample_weight` | in | `std::optional>` | Optional per-sample weights. [len = n_samples] Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::cluster_cost` + +Compute (optionally weighted) cluster cost + +```cpp +void cluster_cost( +const raft::resources& handle, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::host_scalar_view cost, +std::optional> sample_weight = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `cost` | out | `raft::host_scalar_view` | Resulting cluster cost | +| `sample_weight` | in | `std::optional>` | Optional per-sample weights. [len = n_samples] Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `cluster::kmeans::cluster_cost` + +Compute (optionally weighted) cluster cost + +```cpp +void cluster_cost( +const raft::resources& handle, +raft::device_matrix_view X, +raft::device_matrix_view centroids, +raft::host_scalar_view cost, +std::optional> sample_weight = std::nullopt); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | The raft handle | +| `X` | in | `raft::device_matrix_view` | Training instances to cluster. The data must be in row-major format. [dim = n_samples x n_features] | +| `centroids` | in | `raft::device_matrix_view` | Cluster centroids. The data must be in row-major format. [dim = n_clusters x n_features] | +| `cost` | out | `raft::host_scalar_view` | Resulting cluster cost | +| `sample_weight` | in | `std::optional>` | Optional per-sample weights. [len = n_samples] Default: `std::nullopt`. | + +**Returns** + +`void` + +## k-means API helpers + + +### cluster::kmeans::helpers::find_k + +Automatically find the optimal value of k using a binary search. + +```cpp +void find_k(raft::resources const& handle, +raft::device_matrix_view X, +raft::host_scalar_view best_k, +raft::host_scalar_view inertia, +raft::host_scalar_view n_iter, +int kmax, +int kmin = 1, +int maxiter = 100, +float tol = 1e-3); +``` + +This method maximizes the Calinski-Harabasz Index while minimizing the per-cluster inertia. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | | `raft::resources const&` | raft handle | +| `X` | | `raft::device_matrix_view` | input observations (shape n_samples, n_dims) | +| `best_k` | | `raft::host_scalar_view` | best k found from binary search | +| `inertia` | | `raft::host_scalar_view` | inertia of best k found | +| `n_iter` | | `raft::host_scalar_view` | number of iterations used to find best k | +| `kmax` | | `int` | maximum k to try in search | +| `kmin` | | `int` | minimum k to try in search (should be >= 1) Default: `1`. | +| `maxiter` | | `int` | maximum number of iterations to run Default: `100`. | +| `tol` | | `float` | tolerance for early stopping convergence Default: `1e-3`. | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-cluster-spectral.md b/fern/pages/cpp_api/cpp-api-cluster-spectral.md new file mode 100644 index 0000000000..658c0053c7 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-cluster-spectral.md @@ -0,0 +1,112 @@ +--- +slug: api-reference/cpp-api-cluster-spectral +--- + +# Spectral + +_Source header: `cuvs/cluster/spectral.hpp`_ + +## Spectral Clustering Parameters + + +### cluster::spectral::params + +Parameters for spectral clustering + +```cpp +struct params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `n_clusters` | `int` | Number of clusters to find | +| `n_components` | `int` | Number of eigenvectors to use for the spectral embedding (typically equal to n_clusters) | +| `n_init` | `int` | Number of k-means runs with different centroid seeds | +| `n_neighbors` | `int` | Number of nearest neighbors for constructing the connectivity graph | +| `tolerance` | `float` | Tolerance for the eigenvalue solver | +| `rng_state` | `raft::random::RngState` | Random number generator state for reproducibility | + +## Spectral Clustering + + +### cluster::spectral::fit_predict + +Perform spectral clustering on a connectivity graph + +```cpp +void fit_predict(raft::resources const& handle, +params config, +raft::device_coo_matrix_view connectivity_graph, +raft::device_vector_view labels); +``` + +n_clusters-1) + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | RAFT resource handle | +| `config` | in | [`params`](/api-reference/cpp-api-cluster-spectral#cluster-spectral-params) | Spectral clustering parameters | +| `connectivity_graph` | in | `raft::device_coo_matrix_view` | Sparse COO matrix representing connectivity between data points | +| `labels` | out | `raft::device_vector_view` | Device vector of size n_samples to store cluster assignments (0 to | + +**Returns** + +`void` + +**Additional overload:** `cluster::spectral::fit_predict` + +Perform spectral clustering on a connectivity graph + +```cpp +void fit_predict(raft::resources const& handle, +params config, +raft::device_coo_matrix_view connectivity_graph, +raft::device_vector_view labels); +``` + +n_clusters-1) + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | RAFT resource handle | +| `config` | in | [`params`](/api-reference/cpp-api-cluster-spectral#cluster-spectral-params) | Spectral clustering parameters | +| `connectivity_graph` | in | `raft::device_coo_matrix_view` | Sparse COO matrix representing connectivity between data points | +| `labels` | out | `raft::device_vector_view` | Device vector of size n_samples to store cluster assignments (0 to | + +**Returns** + +`void` + +**Additional overload:** `cluster::spectral::fit_predict` + +Perform spectral clustering on a dense dataset + +```cpp +void fit_predict(raft::resources const& handle, +params config, +raft::device_matrix_view dataset, +raft::device_vector_view labels); +``` + +This overload automatically constructs the connectivity graph from the input dataset using k-nearest neighbors. + +n_clusters-1) + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | RAFT resource handle | +| `config` | in | [`params`](/api-reference/cpp-api-cluster-spectral#cluster-spectral-params) | Spectral clustering parameters | +| `dataset` | in | `raft::device_matrix_view` | Dense row-major matrix of shape (n_samples, n_features) | +| `labels` | out | `raft::device_vector_view` | Device vector of size n_samples to store cluster assignments (0 to | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-distance-distance.md b/fern/pages/cpp_api/cpp-api-distance-distance.md new file mode 100644 index 0000000000..78fbd7b672 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-distance-distance.md @@ -0,0 +1,352 @@ +--- +slug: api-reference/cpp-api-distance-distance +--- + +# Distance + +_Source header: `cuvs/distance/distance.hpp`_ + +## Types + + +### distance::DistanceType + +enum to tell how to compute distance + +```cpp +enum class DistanceType : int { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `L2Expanded` | `0` | +| `CosineExpanded` | `2` | +| `L1` | `3` | +| `L2Unexpanded` | `4` | +| `InnerProduct` | `6` | +| `Linf` | `7` | +| `Canberra` | `8` | +| `LpUnexpanded` | `9` | +| `CorrelationExpanded` | `10` | +| `JaccardExpanded` | `11` | +| `HellingerExpanded` | `12` | +| `Haversine` | `13` | +| `BrayCurtis` | `14` | +| `JensenShannon` | `15` | +| `HammingUnexpanded` | `16` | +| `KLDivergence` | `17` | +| `RusselRaoExpanded` | `18` | +| `DiceExpanded` | `19` | +| `BitwiseHamming` | `20` | +| `Precomputed` | `100` | +| `CustomUDF` | `101` | + + +### distance::DensityKernelType + +Density kernel type for Kernel Density Estimation. + +These are the smoothing kernels used in KDE — distinct from the dot-product kernels (RBF, Polynomial, etc.) in cuvs::distance::kernels used by SVMs. + +```cpp +enum class DensityKernelType : int { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `Gaussian` | `0` | +| `Tophat` | `1` | +| `Epanechnikov` | `2` | +| `Exponential` | `3` | +| `Linear` | `4` | +| `Cosine` | `5` | + + +### distance::kernels::KernelParams + +Parameters for kernel matrices. + +The following kernels are implemented: + +- LINEAR $K(x_1,x_2) = \langle x_1,x_2 \rangle,$ where $\langle , \rangle$ is the dot product +- POLYNOMIAL $K(x_1, x_2) = (\gamma \langle x_1,x_2 \rangle + \mathrm{coef0})^\mathrm{degree}$ +- RBF $K(x_1, x_2) = \exp(- \gamma \lVert x_1-x_2 \rVert^2)$ +- TANH $K(x_1, x_2) = \tanh(\gamma \langle x_1,x_2 \rangle + \mathrm{coef0})$ + +```cpp +struct KernelParams { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `kernel` | `KernelType` | | +| `degree` | `int` | | +| `gamma` | `double` | | +| `coef0` | `double` | | + +## Pairwise Distances API + + +### distance::pairwise_distance + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +double metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `double` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +double metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `double` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute pairwise distances for two matrices + +```cpp +void pairwise_distance( +raft::resources const& handle, +raft::device_matrix_view const x, +raft::device_matrix_view const y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +Note: Only contiguous row- or column-major layouts supported currently. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft handle for managing expensive resources | +| `x` | in | `raft::device_matrix_view const` | first set of points (size n*k) | +| `y` | in | `raft::device_matrix_view const` | second set of points (size m*k) | +| `dist` | out | `raft::device_matrix_view` | output distance matrix (size n*m) | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance to evaluate | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute sparse pairwise distances between x and y, using the provided + +```cpp +void pairwise_distance(raft::resources const& handle, +raft::device_csr_matrix_view x, +raft::device_csr_matrix_view y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +input configuration and distance function. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft::resources | +| `x` | in | `raft::device_csr_matrix_view` | raft::device_csr_matrix_view | +| `y` | in | `raft::device_csr_matrix_view` | raft::device_csr_matrix_view | +| `dist` | out | `raft::device_matrix_view` | raft::device_matrix_view dense matrix | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance metric to use | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` + +**Additional overload:** `distance::pairwise_distance` + +Compute sparse pairwise distances between x and y, using the provided + +```cpp +void pairwise_distance(raft::resources const& handle, +raft::device_csr_matrix_view x, +raft::device_csr_matrix_view y, +raft::device_matrix_view dist, +cuvs::distance::DistanceType metric, +float metric_arg = 2.0f); +``` + +input configuration and distance function. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft::resources | +| `x` | in | `raft::device_csr_matrix_view` | raft::device_csr_matrix_view | +| `y` | in | `raft::device_csr_matrix_view` | raft::device_csr_matrix_view | +| `dist` | out | `raft::device_matrix_view` | raft::device_matrix_view dense matrix | +| `metric` | in | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | distance metric to use | +| `metric_arg` | in | `float` | metric argument (used for Minkowski distance) Default: `2.0f`. | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-distance-grammian.md b/fern/pages/cpp_api/cpp-api-distance-grammian.md new file mode 100644 index 0000000000..173101c759 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-distance-grammian.md @@ -0,0 +1,56 @@ +--- +slug: api-reference/cpp-api-distance-grammian +--- + +# Grammian + +_Source header: `cuvs/distance/grammian.hpp`_ + +## Types + + +### distance::kernels::GramMatrixBase + +Base class for general Gram matrices + +A Gram matrix is the Hermitian matrix of inner probucts G_ik = <x_i, x_k> Here, the inner product is evaluated for all elements from vectors sets X1, and X2. + +To be more precise, on exit the output buffer will store: + +- if is_row_major == true: out[j+k*n1] = <x1_j, x2_k>, +- if is_row_major == false: out[j*n2 + k] = <x1_j, x2_k>, where x1_j is the j-th vector from the x1 set and x2_k is the k-th vector from the x2 set. + +```cpp +template +class GramMatrixBase { ... }; +``` + + +### distance::kernels::PolynomialKernel + +Create a kernel matrix using polynomial kernel function. + +```cpp +template +class PolynomialKernel : public GramMatrixBase { ... }; +``` + + +### distance::kernels::TanhKernel + +Create a kernel matrix using tanh kernel function. + +```cpp +template +class TanhKernel : public GramMatrixBase { ... }; +``` + + +### distance::kernels::RBFKernel + +Create a kernel matrix using RBF kernel function. + +```cpp +template +class RBFKernel : public GramMatrixBase { ... }; +``` diff --git a/fern/pages/cpp_api/cpp-api-neighbors-all-neighbors.md b/fern/pages/cpp_api/cpp-api-neighbors-all-neighbors.md new file mode 100644 index 0000000000..a20f013554 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-neighbors-all-neighbors.md @@ -0,0 +1,117 @@ +--- +slug: api-reference/cpp-api-neighbors-all-neighbors +--- + +# All Neighbors + +_Source header: `cuvs/neighbors/all_neighbors.hpp`_ + +## The all-neighbors algorithm parameters. + + +### GraphBuildParams + +The all-neighbors algorithm parameters. + +```cpp +using GraphBuildParams = std::variant; +``` + + +### neighbors::all_neighbors::all_neighbors_params + +Parameters used to build an all-neighbors graph (find nearest neighbors for all the + +training vectors). For scalability, the all-neighbors graph construction algorithm partitions a set of training vectors into overlapping clusters, computes a local knn graph on each cluster, and merges the local graphs into a single global graph. Device memory usage and accuracy can be configured by changing the `overlap_factor` and `n_clusters`. The algorithm used to build each local graph is also configurable. + +```cpp +struct all_neighbors_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `graph_build_params` | [`GraphBuildParams`](/api-reference/cpp-api-neighbors-all-neighbors#graphbuildparams) | Parameters for knn graph building algorithm Approximate nearest neighbors methods or a brute force approach are supported to build the knn graph. Currently supported options are 'IVF-PQ', 'NN Descent', or 'Brute Force'. IVF-PQ is more accurate, but slower compared to NN Descent. Note that 'Brute Force' can also be approximate if n_clusters > 1. Set ivf_pq_params, nn_descent_params, or brute_force_params to select the graph build algorithm and control their parameters. | +| `overlap_factor` | `size_t` | Number of nearest clusters each data point will be assigned to in the batching algorithm. Start with `overlap_factor = 2` and gradually increase (2->3->4 ...) for better accuracy at the cost of device memory usage. | +| `n_clusters` | `size_t` | Number of total clusters (aka batches) to split the data into. If set to 1, algorithm creates an all-neighbors graph without batching. Start with `n_clusters = 4` and increase (4 → 8 → 16...) for less device memory usage at the cost of accuracy. This is independent from `overlap_factor` as long as `overlap_factor` < `n_clusters`. The ratio of `overlap_factor / n_clusters` determines device memory usage. Approximately `(overlap_factor / n_clusters) * num_rows_in_entire_data` number of rows will be put on device memory at once. E.g. between `(overlap_factor / n_clusters)` = 2/10 and 2/20, the latter will use less device memory. Larger `overlap_factor` results in better accuracy of the final all-neighbors knn graph. E.g. While using similar device memory, `(overlap_factor / n_clusters)` = 4/20 will have better accuracy than 2/10 at the cost of performance. | +| `metric` | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | Metric used. | + +## The all-neighbors knn graph build + + +### neighbors::all_neighbors::build + +Builds an approximate all-neighbors knn graph (find nearest neighbors for all the + +```cpp +void build( +const raft::resources& handle, +const all_neighbors_params& params, +raft::host_matrix_view dataset, +raft::device_matrix_view indices, +std::optional> distances = std::nullopt, +std::optional> core_distances = std::nullopt, +float alpha = 1.0); +``` + +training vectors) + +Usage example: + +compute core_distances. If core_distances is given, the resulting indices and distances will be mutual reachability space. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | raft::resources is an object managing resources | +| `params` | in | [`const all_neighbors_params&`](/api-reference/cpp-api-neighbors-all-neighbors#neighbors-all-neighbors-all-neighbors-params) | an instance of all_neighbors::all_neighbors_params that are parameters to build all-neighbors knn graph | +| `dataset` | in | `raft::host_matrix_view` | raft::host_matrix_view input dataset expected to be located in host memory | +| `indices` | out | `raft::device_matrix_view` | nearest neighbor indices of shape [n_row x k] | +| `distances` | out | `std::optional>` | nearest neighbor distances [n_row x k] Default: `std::nullopt`. | +| `core_distances` | out | `std::optional>` | array for core distances of size [n_row]. Requires distances matrix to Default: `std::nullopt`. | +| `alpha` | in | `float` | distance scaling parameter as used in robust single linkage. Default: `1.0`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::all_neighbors::build` + +Builds an approximate all-neighbors knn graph (find nearest neighbors for all the training + +```cpp +void build( +const raft::resources& handle, +const all_neighbors_params& params, +raft::device_matrix_view dataset, +raft::device_matrix_view indices, +std::optional> distances = std::nullopt, +std::optional> core_distances = std::nullopt, +float alpha = 1.0); +``` + +vectors) params.n_clusters should be 1 for data on device. To use a larger params.n_clusters for efficient device memory usage, put data on host RAM. + +Usage example: + +compute core_distances. If core_distances is given, the resulting indices and distances will be mutual reachability space. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `const raft::resources&` | raft::resources is an object managing resources | +| `params` | in | [`const all_neighbors_params&`](/api-reference/cpp-api-neighbors-all-neighbors#neighbors-all-neighbors-all-neighbors-params) | an instance of all_neighbors::all_neighbors_params that are parameters to build all-neighbors knn graph | +| `dataset` | in | `raft::device_matrix_view` | raft::device_matrix_view input dataset expected to be located in device memory | +| `indices` | out | `raft::device_matrix_view` | nearest neighbor indices of shape [n_row x k] | +| `distances` | out | `std::optional>` | nearest neighbor distances [n_row x k] Default: `std::nullopt`. | +| `core_distances` | out | `std::optional>` | array for core distances of size [n_row]. Requires distances matrix to Default: `std::nullopt`. | +| `alpha` | in | `float` | distance scaling parameter as used in robust single linkage. Default: `1.0`. | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-neighbors-ball-cover.md b/fern/pages/cpp_api/cpp-api-neighbors-ball-cover.md new file mode 100644 index 0000000000..4e00baa7bf --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-neighbors-ball-cover.md @@ -0,0 +1,58 @@ +--- +slug: api-reference/cpp-api-neighbors-ball-cover +--- + +# Ball Cover + +_Source header: `cuvs/neighbors/ball_cover.hpp`_ + +## Types + + +### neighbors::ball_cover::index + +Stores raw index data points, sampled landmarks, the 1-nns of index points + +to their closest landmarks, and the ball radii of each landmark. This class is intended to be constructed once and reused across subsequent queries. + +```cpp +template +struct index : cuvs::neighbors::index { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `handle` | `raft::resources const&` | | +| `m` | `int64_t` | | +| `n` | `int64_t` | | +| `n_landmarks` | `int64_t` | | +| `X` | `raft::device_matrix_view` | | +| `metric` | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | + +## Random Ball Cover algorithm + + +### neighbors::ball_cover::build + +Builds and populates a previously unbuilt cuvs::neighbors::ball_cover::index + +```cpp +void build(raft::resources const& handle, index& index); +``` + +Usage example: + +cuvs::neighbors::ball_cover::index + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | library resource management handle | +| `index` | inout | [`index&`](/api-reference/cpp-api-neighbors-ball-cover#neighbors-ball-cover-index) | an empty (and not previous built) instance of | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-neighbors-brute-force.md b/fern/pages/cpp_api/cpp-api-neighbors-brute-force.md new file mode 100644 index 0000000000..527bf8762b --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-neighbors-brute-force.md @@ -0,0 +1,759 @@ +--- +slug: api-reference/cpp-api-neighbors-brute-force +--- + +# Brute Force + +_Source header: `cuvs/neighbors/brute_force.hpp`_ + +## Bruteforce index + + +### neighbors::brute_force::index + +Brute Force index. + +The index stores the dataset and norms for the dataset in device memory. + +```cpp +template +struct index : cuvs::neighbors::index { ... }; +``` + + +### neighbors::brute_force::index::index + +Construct an empty index. + +```cpp +index(raft::resources const& handle); +``` + +Constructs an empty index. This index will either need to be trained with `build` or loaded from a saved copy with `deserialize` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | | `raft::resources const&` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::index` + +Construct a brute force index from dataset + +```cpp +index(raft::resources const& res, +raft::host_matrix_view dataset_view, +std::optional>&& norms, +cuvs::distance::DistanceType metric, +DistT metric_arg = 0.0); +``` + +Constructs a brute force index from a dataset. This lets us precompute norms for the dataset, providing a speed benefit over doing this at query time. This index will copy the host dataset onto the device, and take ownership of any precaculated norms. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset_view` | | `raft::host_matrix_view` | | +| `norms` | | `std::optional>&&` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `DistT` | Default: `0.0`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::index` + +Construct a brute force index from dataset + +```cpp +index(raft::resources const& res, +raft::device_matrix_view dataset_view, +std::optional>&& norms, +cuvs::distance::DistanceType metric, +DistT metric_arg = 0.0); +``` + +Constructs a brute force index from a dataset. This lets us precompute norms for the dataset, providing a speed benefit over doing this at query time. This index will store a non-owning reference to the dataset, but will move any norms supplied. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset_view` | | `raft::device_matrix_view` | | +| `norms` | | `std::optional>&&` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `DistT` | Default: `0.0`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::index` + +Construct a brute force index from dataset + +```cpp +index(raft::resources const& res, +raft::device_matrix_view dataset_view, +std::optional> norms_view, +cuvs::distance::DistanceType metric, +DistT metric_arg = 0.0); +``` + +This class stores a non-owning reference to the dataset and norms. Having precomputed norms gives us a performance advantage at query time. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset_view` | | `raft::device_matrix_view` | | +| `norms_view` | | `std::optional>` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `DistT` | Default: `0.0`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::index` + +Construct a brute force index from dataset + +```cpp +index(raft::resources const& res, +raft::device_matrix_view dataset_view, +std::optional>&& norms, +cuvs::distance::DistanceType metric, +DistT metric_arg = 0.0); +``` + +Constructs a brute force index from a dataset. This lets us precompute norms for the dataset, providing a speed benefit over doing this at query time. This index will store a non-owning reference to the dataset, but will move any norms supplied. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset_view` | | `raft::device_matrix_view` | | +| `norms` | | `std::optional>&&` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `DistT` | Default: `0.0`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::index` + +Construct a brute force index from dataset + +```cpp +index(raft::resources const& res, +raft::device_matrix_view dataset_view, +std::optional> norms_view, +cuvs::distance::DistanceType metric, +DistT metric_arg = 0.0); +``` + +This class stores a non-owning reference to the dataset and norms, with the dataset being supplied on device in a col_major format + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset_view` | | `raft::device_matrix_view` | | +| `norms_view` | | `std::optional>` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `DistT` | Default: `0.0`. | + +**Returns** + +`void` + + +### neighbors::brute_force::index::update_dataset + +Replace the dataset with a new dataset. + +```cpp +void update_dataset(raft::resources const& res, +raft::device_matrix_view dataset); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::device_matrix_view` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::index::update_dataset` + +Replace the dataset with a new dataset. + +```cpp +void update_dataset(raft::resources const& res, +raft::host_matrix_view dataset); +``` + +We create a copy of the dataset on the device. The index manages the lifetime of this copy. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::host_matrix_view` | | + +**Returns** + +`void` + + +### neighbors::brute_force::index::metric + +Distance metric used for retrieval + +```cpp +cuvs::distance::DistanceType metric() const noexcept; +``` + +**Returns** + +[`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) + + +### neighbors::brute_force::index::metric_arg + +Metric argument + +```cpp +DistT metric_arg() const noexcept; +``` + +**Returns** + +`DistT` + + +### neighbors::brute_force::index::size + +Total length of the index (number of vectors). + +```cpp +size_t size() const noexcept; +``` + +**Returns** + +`size_t` + + +### neighbors::brute_force::index::dim + +Dimensionality of the data. + +```cpp +size_t dim() const noexcept; +``` + +**Returns** + +`size_t` + + +### neighbors::brute_force::index::dataset + +Dataset [size, dim] + +```cpp +raft::device_matrix_view dataset() const noexcept; +``` + +**Returns** + +`raft::device_matrix_view` + + +### neighbors::brute_force::index::norms + +Dataset norms + +```cpp +raft::device_vector_view norms() const; +``` + +**Returns** + +`raft::device_vector_view` + + +### neighbors::brute_force::index::has_norms + +Whether ot not this index has dataset norms + +```cpp +inline bool has_norms() const noexcept; +``` + +**Returns** + +`inline bool` + +## Bruteforce index build + + +### neighbors::brute_force::build + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::device_matrix_view` | a device pointer to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +**Additional overload:** `neighbors::brute_force::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::host_matrix_view` | a host pointer to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +**Additional overload:** `neighbors::brute_force::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::device_matrix_view` | a device pointer to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +**Additional overload:** `neighbors::brute_force::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::host_matrix_view` | a host pointer to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +**Additional overload:** `neighbors::brute_force::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::device_matrix_view` | a device pointer to a col-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +**Additional overload:** `neighbors::brute_force::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& handle, +const cuvs::neighbors::brute_force::index_params& index_params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::brute_force::index; +``` + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | | +| `index_params` | in | `const cuvs::neighbors::brute_force::index_params&` | parameters such as the distance metric to use | +| `dataset` | in | `raft::device_matrix_view` | a device pointer to a col-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::brute_force::index`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) + +## Sparse Brute Force index + + +### neighbors::brute_force::sparse_index + +Sparse Brute Force index. + +```cpp +template +struct sparse_index { ... }; +``` + + +### neighbors::brute_force::sparse_index::sparse_index + +Construct a sparse brute force sparse_index from dataset + +```cpp +sparse_index(raft::resources const& res, +raft::device_csr_matrix_view dataset, +cuvs::distance::DistanceType metric, +T metric_arg); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::device_csr_matrix_view` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `metric_arg` | | `T` | | + +**Returns** + +`void` + + +### neighbors::brute_force::sparse_index::metric + +Distance metric used for retrieval + +```cpp +cuvs::distance::DistanceType metric() const noexcept; +``` + +**Returns** + +[`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) + + +### neighbors::brute_force::sparse_index::metric_arg + +Metric argument + +```cpp +T metric_arg() const noexcept; +``` + +**Returns** + +`T` + +## Sparse Brute Force index search + + +### neighbors::brute_force::sparse_search_params + +Sparse Brute Force index search + +```cpp +struct sparse_search_params { ... }; +``` + +## Bruteforce index serialize functions + + +### neighbors::brute_force::serialize + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::brute_force::index& index, +bool include_dataset = true); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +output + +**Template Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `T` | `` | data element type | + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::brute_force::index&`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | +| `include_dataset` | in | `bool` | whether to include the dataset in the serialized Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::serialize` + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::brute_force::index& index, +bool include_dataset = true); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +output + +**Template Parameters** + +| Name | Type | Description | +| --- | --- | --- | +| `T` | `` | data element type | + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::brute_force::index&`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | +| `include_dataset` | in | `bool` | whether to include the dataset in the serialized Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::brute_force::index& index, +bool include_dataset = true); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::brute_force::index&`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::brute_force::index& index, +bool include_dataset = true); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::brute_force::index&`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + + +### neighbors::brute_force::deserialize + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::brute_force::index* index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::brute_force::index*`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::deserialize` + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::brute_force::index* index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::brute_force::index*`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::brute_force::index* index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::brute_force::index*`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::brute_force::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::brute_force::index* index); +``` + +The serialization format can be subject to changes, therefore loading an index saved with a previous version of cuvs is not guaranteed to work. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::brute_force::index*`](/api-reference/cpp-api-neighbors-brute-force#neighbors-brute-force-index) | brute force index | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-neighbors-cagra.md b/fern/pages/cpp_api/cpp-api-neighbors-cagra.md new file mode 100644 index 0000000000..ce118d35fd --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-neighbors-cagra.md @@ -0,0 +1,1842 @@ +--- +slug: api-reference/cpp-api-neighbors-cagra +--- + +# Cagra + +_Source header: `cuvs/neighbors/cagra.hpp`_ + +## Types + + +### neighbors::graph_build_params::ace_params + +Specialized parameters for ACE (Augmented Core Extraction) graph build + +```cpp +struct ace_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `npartitions` | `size_t` | Number of partitions for ACE (Augmented Core Extraction) partitioned build. When set to 0 (default), the number of partitions is automatically derived based on available host and GPU memory to maximize partition size while ensuring the build fits in memory. Small values might improve recall but potentially degrade performance and increase memory usage. Partitions should not be too small to prevent issues in KNN graph construction. The partition size is on average 2 * (n_rows / npartitions) * dim * sizeof(T). 2 is because of the core and augmented vectors. Please account for imbalance in the partition sizes (up to 3x in our tests). If the specified number of partitions results in partitions that exceed available memory, the value will be automatically increased to fit memory constraints and a warning will be issued. | +| `ef_construction` | `size_t` | The index quality for the ACE build. Bigger values increase the index quality. At some point, increasing this will no longer improve the quality. | +| `build_dir` | `std::string` | Directory to store ACE build artifacts (e.g., KNN graph, optimized graph). Used when `use_disk` is true or when the graph does not fit in host and GPU memory. This should be the fastest disk in the system and hold enough space for twice the dataset, final graph, and label mapping. | +| `use_disk` | `bool` | Whether to use disk-based storage for ACE build. When true, enables disk-based operations for memory-efficient graph construction. | +| `max_host_memory_gb` | `double` | Maximum host memory to use for ACE build in GiB. When set to 0 (default), uses available host memory. When set to a positive value, limits host memory usage to the specified amount. Useful for testing or when running alongside other memory-intensive processes. | +| `max_gpu_memory_gb` | `double` | Maximum GPU memory to use for ACE build in GiB. When set to 0 (default), uses available GPU memory. When set to a positive value, limits GPU memory usage to the specified amount. Useful for testing or when running alongside other memory-intensive processes. | + +## CAGRA index build parameters + + +### neighbors::vpq_params + +Parameters for VPQ compression. + +```cpp +struct vpq_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `pq_bits` | `uint32_t` | The bit length of the vector element after compression by PQ. Possible values: [4, 5, 6, 7, 8]. Hint: the smaller the 'pq_bits', the smaller the index size and the better the search performance, but the lower the recall. | +| `pq_dim` | `uint32_t` | The dimensionality of the vector after compression by PQ. When zero, an optimal value is selected using a heuristic. TODO: at the moment `dim` must be a multiple `pq_dim`. | +| `vq_n_centers` | `uint32_t` | Vector Quantization (VQ) codebook size - number of "coarse cluster centers". When zero, an optimal value is selected using a heuristic. | +| `kmeans_n_iters` | `uint32_t` | The number of iterations searching for kmeans centers (both VQ & PQ phases). | +| `vq_kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building (VQ phase). When zero, an optimal value is selected using a heuristic. | +| `pq_kmeans_trainset_fraction` | `double` | The fraction of data to use during iterative kmeans building (PQ phase). When zero, an optimal value is selected using a heuristic. | +| `pq_kmeans_type` | [`cuvs::cluster::kmeans::kmeans_type`](/api-reference/cpp-api-cluster-kmeans#cluster-kmeans-kmeans-type) | Type of k-means algorithm for PQ training. Balanced k-means tends to be faster than regular k-means for PQ training, for problem sets where the number of points per cluster are approximately equal. Regular k-means may be better for skewed cluster distributions. | +| `max_train_points_per_pq_code` | `uint32_t` | The max number of data points to use per PQ code during PQ codebook training. Using more data points per PQ code may increase the quality of PQ codebook but may also increase the build time. We will use `pq_n_centers * max_train_points_per_pq_code` training points to train each PQ codebook. | +| `max_train_points_per_vq_cluster` | `uint32_t` | The max number of data points to use per VQ cluster during training. | + + +### neighbors::cagra::hnsw_heuristic_type + +A strategy for selecting the graph build parameters based on similar HNSW index + +parameters. + +Define how `cagra::index_params::from_hnsw_params` should construct a graph to construct a graph that is to be converted to (used by) a CPU HNSW index. + +```cpp +enum class hnsw_heuristic_type : uint32_t { ... }; +``` + + +### neighbors::cagra::index_params::from_hnsw_params + +Create a CAGRA index parameters compatible with HNSW index + +```cpp +static cagra::index_params from_hnsw_params( +raft::matrix_extent dataset, +int M, +int ef_construction, +hnsw_heuristic_type heuristic = hnsw_heuristic_type::SIMILAR_SEARCH_PERFORMANCE, +cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded); +``` + +* IMPORTANT NOTE * + +The reference HNSW index and the corresponding from-CAGRA generated HNSW index will NOT produce exactly the same recalls and QPS for the same parameter `ef`. The graphs are different internally. Depending on the selected heuristics, the CAGRA-produced graph's QPS-Recall curve may be shifted along the curve right or left. See the heuristics descriptions for more details. + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `dataset` | | `raft::matrix_extent` | The shape of the input dataset | +| `M` | | `int` | HNSW index parameter M | +| `ef_construction` | | `int` | HNSW index parameter ef_construction | +| `heuristic` | | [`hnsw_heuristic_type`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-hnsw-heuristic-type) | The heuristic to use for selecting the graph build parameters Default: `hnsw_heuristic_type::SIMILAR_SEARCH_PERFORMANCE`. | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | The distance metric to search Default: `cuvs::distance::DistanceType::L2Expanded`. | + +**Returns** + +`static cagra::index_params` + +## CAGRA index search parameters + + +### neighbors::cagra::search_algo + +CAGRA index search parameters + +```cpp +enum class search_algo { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `SINGLE_CTA` | `0` | +| `MULTI_CTA` | `1` | +| `MULTI_KERNEL` | `2` | +| `AUTO` | `100` | + +## CAGRA index extend parameters + + +### neighbors::cagra::extend_params + +CAGRA index extend parameters + +```cpp +struct extend_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `max_chunk_size` | `uint32_t` | The additional dataset is divided into chunks and added to the graph. This is the knob to adjust the tradeoff between the recall and operation throughput. Large chunk sizes can result in high throughput, but use more working memory (O(max_chunk_size*degree^2)). This can also degrade recall because no edges are added between the nodes in the same chunk. Auto select when 0. | + +## CAGRA index type + + +### neighbors::cagra::index + +CAGRA index. + +The index stores the dataset and a kNN graph in device memory. + +```cpp +template +struct index : cuvs::neighbors::index { ... }; +``` + + +### neighbors::cagra::index::metric + +Distance metric used for clustering. + +```cpp +[[nodiscard]] constexpr inline auto metric() const noexcept -> cuvs::distance::DistanceType; +``` + +**Returns** + +[`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) + + +### neighbors::cagra::index::size + +Total length of the index (number of vectors). + +```cpp +[[nodiscard]] constexpr inline auto size() const noexcept -> IdxT; +``` + +**Returns** + +`IdxT` + + +### neighbors::cagra::index::dim + +Dimensionality of the data. + +```cpp +[[nodiscard]] constexpr inline auto dim() const noexcept -> uint32_t; +``` + +**Returns** + +`uint32_t` + + +### neighbors::cagra::index::graph_degree + +Graph degree + +```cpp +[[nodiscard]] constexpr inline auto graph_degree() const noexcept -> uint32_t; +``` + +**Returns** + +`uint32_t` + + +### neighbors::cagra::index::data + +Dataset [size, dim] + +```cpp +[[nodiscard]] inline auto data() const noexcept -> const cuvs::neighbors::dataset&; +``` + +**Returns** + +[`const cuvs::neighbors::dataset&`](/api-reference/cpp-api-neighbors-common#neighbors-dataset) + + +### neighbors::cagra::index::graph + +neighborhood graph [size, graph-degree] + +```cpp +[[nodiscard]] inline auto graph() const noexcept +-> raft::device_matrix_view; +``` + +**Returns** + +`raft::device_matrix_view` + + +### neighbors::cagra::index::source_indices + +Mapping from internal graph node indices to the original user-provided indices. + +```cpp +[[nodiscard]] inline auto source_indices() const noexcept +-> std::optional>; +``` + +**Returns** + +`std::optional>` + + +### neighbors::cagra::index::dataset_fd + +Get the dataset file descriptor (for disk-backed index) + +```cpp +[[nodiscard]] inline auto dataset_fd() const noexcept +-> const std::optional&; +``` + +**Returns** + +[`const std::optional&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) + + +### neighbors::cagra::index::graph_fd + +Get the graph file descriptor (for disk-backed index) + +```cpp +[[nodiscard]] inline auto graph_fd() const noexcept +-> const std::optional&; +``` + +**Returns** + +[`const std::optional&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) + + +### neighbors::cagra::index::mapping_fd + +Get the mapping file descriptor (for disk-backed index) + +```cpp +[[nodiscard]] inline auto mapping_fd() const noexcept +-> const std::optional&; +``` + +**Returns** + +[`const std::optional&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) + + +### neighbors::cagra::index::dataset_norms + +Dataset norms for cosine distance [size] + +```cpp +[[nodiscard]] inline auto dataset_norms() const noexcept +-> std::optional>; +``` + +**Returns** + +`std::optional>` + + +### neighbors::cagra::index::index + +```cpp +index(const index&) = delete; +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `arg1` | | [`const index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::index` + +Construct an empty index. + +```cpp +index(raft::resources const& res, +cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded) +: cuvs::neighbors::index(), +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | Default: `cuvs::distance::DistanceType::L2Expanded`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::index` + +Construct an index from dataset and knn_graph arrays + +```cpp +template +index(raft::resources const& res, +cuvs::distance::DistanceType metric, +raft::mdspan, raft::row_major, data_accessor> dataset, +raft::mdspan, +raft::row_major, +graph_accessor> knn_graph) +: cuvs::neighbors::index(), +``` + +If the dataset and graph is already in GPU memory, then the index is just a thin wrapper around these that stores a non-owning a reference to the arrays. + +The constructor also accepts host arrays. In that case they are copied to the device, and the device arrays will be owned by the index. + +In case the dasates rows are not 16 bytes aligned, then we create a padded copy in device memory to ensure alignment for vectorized load. + +Usage examples: + +- Cagra index is normally created by the cagra::build In the above example, we have passed a host dataset to build. The returned index will own a device copy of the dataset and the knn_graph. In contrast, if we pass the dataset as a device_mdspan to build, then it will only store a reference to it. + +- Constructing index using existing knn-graph + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `metric` | | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | | +| `dataset` | | `raft::mdspan, raft::row_major, data_accessor>` | | +| `knn_graph` | | `raft::mdspan, raft::row_major, graph_accessor>` | | + +**Returns** + +`void` + + +### neighbors::cagra::index::update_dataset + +Replace the dataset with a new dataset. + +```cpp +void update_dataset(raft::resources const& res, +raft::device_matrix_view dataset); +``` + +If the new dataset rows are aligned on 16 bytes, then only a reference is stored to the dataset. It is the caller's responsibility to ensure that dataset stays alive as long as the index. It is expected that the same set of vectors are used for update_dataset and index build. + +Note: This will clear any precomputed dataset norms. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::device_matrix_view` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_dataset` + +Set the dataset reference explicitly to a device matrix view with padding. + +```cpp +void update_dataset(raft::resources const& res, +raft::device_matrix_view dataset); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::device_matrix_view` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_dataset` + +Replace the dataset with a new dataset. + +```cpp +void update_dataset(raft::resources const& res, +raft::host_matrix_view dataset); +``` + +We create a copy of the dataset on the device. The index manages the lifetime of this copy. It is expected that the same set of vectors are used for update_dataset and index build. + +Note: This will clear any precomputed dataset norms. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `raft::host_matrix_view` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_dataset` + +Replace the dataset with a new dataset. It is expected that the same set of vectors are used + +```cpp +template +auto update_dataset(raft::resources const& res, DatasetT&& dataset) +-> std::enable_if_t, DatasetT>>; +``` + +for update_dataset and index build. + +Note: This will clear any precomputed dataset norms. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `dataset` | | `DatasetT&&` | | + +**Returns** + +[`std::enable_if_t, DatasetT>>`](/api-reference/cpp-api-neighbors-common#neighbors-dataset) + + +### neighbors::cagra::index::update_graph + +Replace the graph with a new graph. + +```cpp +void update_graph( +raft::resources const& res, +raft::device_matrix_view knn_graph); +``` + +Since the new graph is a device array, we store a reference to that, and it is the caller's responsibility to ensure that knn_graph stays alive as long as the index. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `knn_graph` | | `raft::device_matrix_view` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_graph` + +Replace the graph with a new graph. + +```cpp +void update_graph( +raft::resources const& res, +raft::host_matrix_view knn_graph); +``` + +We create a copy of the graph on the device. The index manages the lifetime of this copy. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `knn_graph` | | `raft::host_matrix_view` | | + +**Returns** + +`void` + + +### neighbors::cagra::index::update_source_indices + +Replace the source indices with a new source indices taking the ownership of the passed vector. + +```cpp +void update_source_indices(raft::device_vector&& source_indices); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `source_indices` | | `raft::device_vector&&` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_source_indices` + +Copy the provided source indices into the index. + +```cpp +template +void update_source_indices( +raft::resources const& res, +raft::mdspan, raft::row_major, Accessor> +source_indices); +``` + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | | `raft::resources const&` | | +| `source_indices` | | `raft::mdspan, raft::row_major, Accessor>` | | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_dataset` + +Update the dataset from a disk file using a file descriptor. + +```cpp +void update_dataset(raft::resources const& res, cuvs::util::file_descriptor&& fd); +``` + +This method configures the index to use a disk-based dataset. The dataset file should contain a numpy header followed by vectors in row-major format. The number of rows and dimensionality are read from the numpy header. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | raft resources | +| `fd` | in | [`cuvs::util::file_descriptor&&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) | File descriptor (will be moved into the index for lifetime management) | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::index::update_graph` + +Update the graph from a disk file using a file descriptor. + +```cpp +void update_graph(raft::resources const& res, cuvs::util::file_descriptor&& fd); +``` + +This method configures the index to use a disk-based graph. The graph file should contain a numpy header followed by neighbor indices in row-major format. The number of rows and graph degree are read from the numpy header. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | raft resources | +| `fd` | in | [`cuvs::util::file_descriptor&&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) | File descriptor (will be moved into the index for lifetime management) | + +**Returns** + +`void` + + +### neighbors::cagra::index::update_mapping + +Update the dataset mapping from a disk file using a file descriptor. + +```cpp +void update_mapping(raft::resources const& res, cuvs::util::file_descriptor&& fd); +``` + +This method configures the index to use a disk-based dataset mapping. The mapping file should contain a numpy header followed by index mappings. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | raft resources | +| `fd` | in | [`cuvs::util::file_descriptor&&`](/api-reference/cpp-api-util-file-io#util-file-descriptor) | File descriptor (will be moved into the index for lifetime management) | + +**Returns** + +`void` + +## CAGRA index build functions + + +### neighbors::cagra::build + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::device_matrix_view` | a matrix view (device) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::host_matrix_view` | a matrix view (host) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::device_matrix_view` | a matrix view (device) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::host_matrix_view` | a matrix view (host) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) +- BitwiseHamming (currently only supported with NN-Descent and Iterative Search as the build algorithm, and only for int8_t and uint8_t data types) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::device_matrix_view` | a matrix view (device) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) +- BitwiseHamming (currently only supported with NN-Descent and Iterative Search as the build algorithm, and only for int8_t and uint8_t data types) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::host_matrix_view` | a matrix view (host) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::device_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) +- BitwiseHamming (currently only supported with NN-Descent and Iterative Search as the build algorithm, and only for int8_t and uint8_t data types) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::device_matrix_view` | a matrix view (device) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +**Additional overload:** `neighbors::cagra::build` + +Build the index from the dataset for efficient search. + +```cpp +auto build(raft::resources const& res, +const cuvs::neighbors::cagra::index_params& params, +raft::host_matrix_view dataset) +-> cuvs::neighbors::cagra::index; +``` + +The build consist of two steps: build an intermediate knn-graph, and optimize it to create the final graph. The index_params struct controls the node degree of these graphs. + +The following distance metrics are supported: + +- L2 +- InnerProduct (currently only supported with IVF-PQ as the build algorithm) +- CosineExpanded (dataset norms are computed as float regardless of input data type) +- L1 (currently only supported with NN-Descent and Iterative Search as the build algorithm) +- BitwiseHamming (currently only supported with NN-Descent and Iterative Search as the build algorithm, and only for int8_t and uint8_t data types) + +Usage example: + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `res` | in | `raft::resources const&` | | +| `params` | in | `const cuvs::neighbors::cagra::index_params&` | parameters for building the index | +| `dataset` | in | `raft::host_matrix_view` | a matrix view (host) to a row-major matrix [n_rows, dim] | + +**Returns** + +[`cuvs::neighbors::cagra::index`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) + +## CAGRA extend functions + + +### neighbors::cagra::extend + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::device_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::device_matrix_view` | additional dataset on device memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::host_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::host_matrix_view` | additional dataset on host memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::device_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::device_matrix_view` | additional dataset on device memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::host_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::host_matrix_view` | additional dataset on host memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::device_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::device_matrix_view` | additional dataset on device memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::host_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::host_matrix_view` | additional dataset on host memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::device_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::device_matrix_view` | additional dataset on host memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::extend` + +Add new vectors to a CAGRA index + +```cpp +void extend( +raft::resources const& handle, +const cagra::extend_params& params, +raft::host_matrix_view additional_dataset, +cuvs::neighbors::cagra::index& idx, +std::optional> +new_dataset_buffer_view = std::nullopt, +std::optional> new_graph_buffer_view = std::nullopt); +``` + +Usage example: + +part. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets, cols must be the dimension of the dataset, and the stride must be the same as the original index dataset. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the dataset themselves. The data will be copied from the current index in this function. The num rows must be the sum of the original and additional datasets and cols must be the graph degree. This view will be stored in the output index. It is the caller's responsibility to ensure that dataset stays alive as long as the index. This option is useful when users want to manage the memory space for the graph themselves. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | raft resources | +| `params` | in | [`const cagra::extend_params&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-extend-params) | extend params | +| `additional_dataset` | in | `raft::host_matrix_view` | additional dataset on host memory | +| `idx` | in,out | [`cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `new_dataset_buffer_view` | out | `std::optional>` | memory buffer view for the dataset including the additional Default: `std::nullopt`. | +| `new_graph_buffer_view` | out | `std::optional>` | memory buffer view for the graph including the additional part. Default: `std::nullopt`. | + +**Returns** + +`void` + +## CAGRA search functions + + +### none_sample_filter + +Search ANN using the constructed index. + +```cpp +void search(raft::resources const& res, +cuvs::neighbors::cagra::search_params const& params, +const cuvs::neighbors::cagra::index& index, +raft::device_matrix_view queries, +raft::device_matrix_view neighbors, +raft::device_matrix_view distances, +const cuvs::neighbors::filtering::base_filter& sample_filter = +cuvs::neighbors::filtering::none_sample_filter{} +``` + +## CAGRA serialize functions + + +### neighbors::cagra::serialize + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + + +### neighbors::cagra::deserialize + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Save the index to file. + +```cpp +void serialize(raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from file. + +```cpp +void deserialize(raft::resources const& handle, +const std::string& filename, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the name of the file that stores the index | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize` + +Write the index to an output stream + +```cpp +void serialize(raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +bool include_dataset = true); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `include_dataset` | in | `bool` | Whether or not to write out the dataset to the file. Default: `true`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::deserialize` + +Load index from input stream + +```cpp +void deserialize(raft::resources const& handle, +std::istream& is, +cuvs::neighbors::cagra::index* index); +``` + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `is` | in | `std::istream&` | input stream | +| `index` | out | [`cuvs::neighbors::cagra::index*`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | the cagra index | + +**Returns** + +`void` + + +### neighbors::cagra::serialize_to_hnswlib + +Write the CAGRA built index as a base layer HNSW index to an output stream + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Save a CAGRA build index in hnswlib base-layer-only serialized format + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Write the CAGRA built index as a base layer HNSW index to an output stream + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Save a CAGRA build index in hnswlib base-layer-only serialized format + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Write the CAGRA built index as a base layer HNSW index to an output stream + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Save a CAGRA build index in hnswlib base-layer-only serialized format + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Write the CAGRA built index as a base layer HNSW index to an output stream + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +std::ostream& os, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `os` | in | `std::ostream&` | output stream | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` + +**Additional overload:** `neighbors::cagra::serialize_to_hnswlib` + +Save a CAGRA build index in hnswlib base-layer-only serialized format + +```cpp +void serialize_to_hnswlib( +raft::resources const& handle, +const std::string& filename, +const cuvs::neighbors::cagra::index& index, +std::optional> dataset = +std::nullopt); +``` + +NOTE: The saved index can only be read by the hnswlib wrapper in cuVS, as the serialization format is not compatible with the original hnswlib. + +Experimental, both the API and the serialization format are subject to change. + +**Parameters** + +| Name | Direction | Type | Description | +| --- | --- | --- | --- | +| `handle` | in | `raft::resources const&` | the raft handle | +| `filename` | in | `const std::string&` | the file name for saving the index | +| `index` | in | [`const cuvs::neighbors::cagra::index&`](/api-reference/cpp-api-neighbors-cagra#neighbors-cagra-index) | CAGRA index | +| `dataset` | in | `std::optional>` | [optional] host array that stores the dataset, required if the index does not contain the dataset. Default: `std::nullopt`. | + +**Returns** + +`void` diff --git a/fern/pages/cpp_api/cpp-api-neighbors-common.md b/fern/pages/cpp_api/cpp-api-neighbors-common.md new file mode 100644 index 0000000000..d88ecbd189 --- /dev/null +++ b/fern/pages/cpp_api/cpp-api-neighbors-common.md @@ -0,0 +1,365 @@ +--- +slug: api-reference/cpp-api-neighbors-common +--- + +# Common + +_Source header: `cuvs/neighbors/common.hpp`_ + +## Approximate Nearest Neighbors Types + + +### neighbors::index + +The base for approximate KNN index structures. + +```cpp +struct index { ... }; +``` + + +### neighbors::index_params + +The base for KNN index parameters. + +```cpp +struct index_params { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `metric` | [`cuvs::distance::DistanceType`](/api-reference/cpp-api-distance-distance#distance-distancetype) | Distance type. | +| `metric_arg` | `float` | The argument used by some distance metrics. | + + +### neighbors::MergeStrategy + +Strategy for merging indices. + +This enum is declared separately to avoid namespace pollution when including common.hpp. It provides a generic merge strategy that can be used across different index types. + +```cpp +enum class MergeStrategy { ... }; +``` + +**Values** + +| Name | Value | +| --- | --- | +| `MERGE_STRATEGY_PHYSICAL` | `0` | +| `MERGE_STRATEGY_LOGICAL` | `1` | + +## Types + + +### neighbors::dataset + +Two-dimensional dataset; maybe owning, maybe compressed, maybe strided. + +```cpp +template +struct dataset { ... }; +``` + + +### neighbors::vpq_dataset + +VPQ compressed dataset. + +The dataset is compressed using two level quantization + +1. Vector Quantization +2. Product Quantization of residuals + +```cpp +template +struct vpq_dataset : public dataset { ... }; +``` + +**Fields** + +| Name | Type | Description | +| --- | --- | --- | +| `vq_code_book` | `raft::device_matrix` | Vector Quantization codebook - "coarse cluster centers". | +| `pq_code_book` | `raft::device_matrix` | Product Quantization codebook - "fine cluster centers". | +| `data` | `raft::device_matrix` | Compressed dataset. | + + +### neighbors::ivf::list_base + +Abstract base class for IVF list data. + +This allows polymorphic access to list data regardless of the underlying layout. + +TODO: Make this struct internal (tracking issue: https://github.com/rapidsai/cuvs/issues/1726) + +```cpp +template +struct list_base { ... }; +``` + + +### neighbors::ivf::list + +The data for a single IVF list. + +```cpp +template