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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions c/include/cuvs/neighbors/hnsw.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -109,7 +109,7 @@ CUVS_EXPORT cuvsError_t cuvsHnswAceParamsDestroy(cuvsHnswAceParams_t params);
struct cuvsHnswIndexParams {
/* hierarchy of the hnsw index */
enum cuvsHnswHierarchy hierarchy;
/** Size of the candidate list during hierarchy construction when hierarchy is `CPU`*/
/** Maximum candidate list size used during index construction. */
int ef_construction;
/** Number of host threads to use to construct hierarchy when hierarchy is `CPU` or `GPU`.
When the value is 0, the number of threads is automatically determined to the
Expand All @@ -119,15 +119,15 @@ struct cuvsHnswIndexParams {
is parallelized with the help of CPU threads.
*/
int num_threads;
/** HNSW M parameter: number of bi-directional links per node (used when building with ACE).
* graph_degree = m * 2, intermediate_graph_degree = m * 3.
/** HNSW M parameter: number of bi-directional links per node. When the graph is built on the GPU,
* this parameter is used to derive the internal CAGRA graph build parameters.
*/
size_t M;
/** Distance type for the index. */
cuvsDistanceType metric;
/**
* Optional: specify ACE parameters for building HNSW index using ACE algorithm.
* Set to nullptr for default behavior (from_cagra conversion).
* Optional ACE parameters for out-of-core graph construction.
* Set to nullptr to select the graph build algorithm automatically.
*/
cuvsHnswAceParams_t ace_params;
};
Expand Down Expand Up @@ -285,22 +285,20 @@ CUVS_EXPORT cuvsError_t cuvsHnswFromCagraWithDataset(cuvsResources_t res,
*/

/**
* @defgroup hnsw_c_index_build Build HNSW index using ACE algorithm
* @defgroup hnsw_c_index_build Build an HNSW index
* @{
*/

/**
* @brief Build an HNSW index using ACE (Augmented Core Extraction) algorithm.
* @brief Build an HNSW index from HNSW parameters.
*
* 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
* The graph is built on the GPU and converted to an HNSW index that can be searched on the CPU.
* The graph build algorithm is selected automatically unless explicit ACE parameters are provided.
*
* NOTE: This function requires CUDA to be available at runtime.
*
* @param[in] res cuvsResources_t opaque C handle
* @param[in] params cuvsHnswIndexParams_t with ACE parameters configured
* @param[in] params cuvsHnswIndexParams_t with HNSW build parameters
* @param[in] dataset DLManagedTensor* host dataset to build index from
* @param[out] index cuvsHnswIndex_t to return the built HNSW index
*
Expand All @@ -314,18 +312,10 @@ CUVS_EXPORT cuvsError_t cuvsHnswFromCagraWithDataset(cuvsResources_t res,
* cuvsResources_t res;
* cuvsResourcesCreate(&res);
*
* // Create ACE parameters
* cuvsHnswAceParams_t ace_params;
* cuvsHnswAceParamsCreate(&ace_params);
* ace_params->npartitions = 4;
* ace_params->use_disk = true;
* ace_params->build_dir = "/tmp/hnsw_ace_build";
*
* // Create index parameters
* cuvsHnswIndexParams_t params;
* cuvsHnswIndexParamsCreate(&params);
* params->hierarchy = GPU;
* params->ace_params = ace_params;
* params->M = 32;
* params->ef_construction = 120;
*
Expand All @@ -340,7 +330,6 @@ CUVS_EXPORT cuvsError_t cuvsHnswFromCagraWithDataset(cuvsResources_t res,
* cuvsHnswBuild(res, params, &dataset, hnsw_index);
*
* // Clean up
* cuvsHnswAceParamsDestroy(ace_params);
* cuvsHnswIndexParamsDestroy(params);
* cuvsHnswIndexDestroy(hnsw_index);
* cuvsResourcesDestroy(res);
Expand Down
22 changes: 12 additions & 10 deletions c/src/neighbors/hnsw.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -37,15 +37,17 @@ void _build(cuvsResources_t res,
cpp_params.M = params->M;
cpp_params.metric = static_cast<cuvs::distance::DistanceType>(params->metric);

// Configure ACE parameters
RAFT_EXPECTS(params->ace_params != nullptr, "ACE parameters must be set for hnsw::build");
auto ace_params = cuvs::neighbors::hnsw::graph_build_params::ace_params();
ace_params.npartitions = params->ace_params->npartitions;
ace_params.build_dir = params->ace_params->build_dir ? params->ace_params->build_dir : "/tmp/hnsw_ace_build";
ace_params.use_disk = params->ace_params->use_disk;
ace_params.max_host_memory_gb = params->ace_params->max_host_memory_gb;
ace_params.max_gpu_memory_gb = params->ace_params->max_gpu_memory_gb;
cpp_params.graph_build_params = ace_params;
if (params->ace_params != nullptr) {
auto ace_params = cuvs::neighbors::hnsw::graph_build_params::ace_params();
ace_params.npartitions = params->ace_params->npartitions;
ace_params.build_dir = params->ace_params->build_dir
? params->ace_params->build_dir
: "/tmp/hnsw_ace_build";
ace_params.use_disk = params->ace_params->use_disk;
ace_params.max_host_memory_gb = params->ace_params->max_host_memory_gb;
ace_params.max_gpu_memory_gb = params->ace_params->max_gpu_memory_gb;
cpp_params.graph_build_params = ace_params;
}

using dataset_mdspan_type = raft::host_matrix_view<T const, int64_t, raft::row_major>;
auto dataset_mds = cuvs::core::from_dlpack<dataset_mdspan_type>(dataset_tensor);
Expand Down
33 changes: 32 additions & 1 deletion c/tests/neighbors/ann_hnsw_c.cu
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -123,6 +123,37 @@ TEST(CagraHnswC, BuildSearch)
cuvsResourcesDestroy(res);
}

TEST(HnswC, BuildWithoutAce)
{
cuvsResources_t res;
cuvsResourcesCreate(&res);

DLManagedTensor dataset_tensor;
dataset_tensor.dl_tensor.data = dataset;
dataset_tensor.dl_tensor.device.device_type = kDLCPU;
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] = {4, 2};
dataset_tensor.dl_tensor.shape = dataset_shape;
dataset_tensor.dl_tensor.strides = nullptr;

cuvsHnswIndexParams_t hnsw_params;
cuvsHnswIndexParamsCreate(&hnsw_params);
hnsw_params->M = 2;
hnsw_params->ef_construction = 100;

cuvsHnswIndex_t hnsw_index;
cuvsHnswIndexCreate(&hnsw_index);

ASSERT_EQ(cuvsHnswBuild(res, hnsw_params, &dataset_tensor, hnsw_index), CUVS_SUCCESS);

cuvsHnswIndexParamsDestroy(hnsw_params);
cuvsHnswIndexDestroy(hnsw_index);
cuvsResourcesDestroy(res);
}

TEST(HnswAceC, BuildSearch)
{
// create cuvsResources_t
Expand Down
13 changes: 5 additions & 8 deletions fern/pages/c_api/c-api-neighbors-hnsw.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,12 @@ cuvsHnswIndex_t hnsw_index);

[`cuvsError_t`](/api-reference/c-api-core-c-api#cuvserror-t)

## Build HNSW index using ACE algorithm
## Build an HNSW index

<a id="cuvshnswbuild"></a>
### cuvsHnswBuild

Build an HNSW index using ACE (Augmented Core Extraction) algorithm.
Build an HNSW index from HNSW parameters.

```c
cuvsError_t cuvsHnswBuild(cuvsResources_t res,
Expand All @@ -296,11 +296,8 @@ 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
The graph is built on the GPU and converted to an HNSW index that can be searched on the CPU.
The graph build algorithm is selected automatically unless explicit ACE parameters are provided.

NOTE: This function requires CUDA to be available at runtime.

Expand All @@ -309,7 +306,7 @@ NOTE: This function requires CUDA to be available at runtime.
| 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 |
| `params` | in | `cuvsHnswIndexParams_t` | cuvsHnswIndexParams_t with HNSW build parameters |
| `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 |

Expand Down
13 changes: 4 additions & 9 deletions fern/pages/java_api/java-api-com-nvidia-cuvs-hnswindex.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,16 @@ _Source: `java/cuvs-java/src/main/java/com/nvidia/cuvs/HnswIndex.java:53`_
static HnswIndex build(CuVSResources resources, HnswIndexParams hnswParams, CuVSMatrix dataset) throws Throwable
```

Builds an HNSW index using the ACE (Augmented Core Extraction) algorithm.

ACE enables building HNSW indexes for datasets too large to fit in GPU
memory by partitioning the dataset and building sub-indexes for each
partition independently.

NOTE: This method requires `hnswParams.getAceParams()` to be set with
an instance of HnswAceParams.
Builds an HNSW index from HNSW parameters. The graph is built on the GPU and converted to an
HNSW index that can be searched on the CPU. The graph build algorithm is selected automatically
unless explicit ACE parameters are provided.

**Parameters**

| Name | Description |
| --- | --- |
| `resources` | The CuVS resources |
| `hnswParams` | Parameters for the HNSW index with ACE configuration |
| `hnswParams` | Parameters for the HNSW index |
| `dataset` | The dataset to build the index from |

**Returns**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ public long getM()
```

Gets the HNSW M parameter: number of bi-directional links per node
(used when building with ACE). graph_degree = m * 2,
intermediate_graph_degree = m * 3.
used to derive the internal graph build parameters for GPU construction.

**Returns**

Expand Down Expand Up @@ -112,7 +111,8 @@ _Source: `java/cuvs-java/src/main/java/com/nvidia/cuvs/HnswIndexParams.java:142`
public HnswAceParams getAceParams()
```

Gets the ACE parameters for building HNSW index using ACE algorithm.
Gets the optional ACE parameters for explicit out-of-core graph construction. When not set, the
graph build algorithm is selected automatically.

**Returns**

Expand Down Expand Up @@ -159,14 +159,13 @@ _Source: `java/cuvs-java/src/main/java/com/nvidia/cuvs/HnswIndexParams.java:202`
public Builder withEfConstruction(int efConstruction)
```

Sets the size of the candidate list during hierarchy construction when
hierarchy is `CPU`.
Sets the maximum candidate list size used during index construction.

**Parameters**

| Name | Description |
| --- | --- |
| `efConstruction` | the size of the candidate list during hierarchy construction when hierarchy is `CPU` |
| `efConstruction` | the maximum candidate list size used during construction |

**Returns**

Expand Down Expand Up @@ -222,8 +221,7 @@ public Builder withM(long m)
```

Sets the HNSW M parameter: number of bi-directional links per node
(used when building with ACE). graph_degree = m * 2,
intermediate_graph_degree = m * 3.
used to derive the internal graph build parameters for GPU construction.

**Parameters**

Expand Down Expand Up @@ -263,7 +261,8 @@ _Source: `java/cuvs-java/src/main/java/com/nvidia/cuvs/HnswIndexParams.java:262`
public Builder withAceParams(HnswAceParams aceParams)
```

Sets the ACE parameters for building HNSW index using ACE algorithm.
Sets optional ACE parameters for explicit out-of-core graph construction. When not set, the graph
build algorithm is selected automatically.

**Parameters**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,14 @@ _Source: `java/cuvs-java/src/main/java/com/nvidia/cuvs/spi/CuVSProvider.java:123
HnswIndex hnswIndexBuild(CuVSResources resources, HnswIndexParams hnswParams, CuVSMatrix dataset) throws Throwable
```

Builds an HNSW index using the ACE (Augmented Core Extraction) algorithm.
Builds an HNSW index from HNSW parameters using GPU graph construction.

**Parameters**

| Name | Description |
| --- | --- |
| `resources` | The CuVS resources |
| `hnswParams` | Parameters for the HNSW index with ACE configuration |
| `hnswParams` | Parameters for the HNSW index |
| `dataset` | The dataset to build the index from |

**Returns**
Expand Down
29 changes: 9 additions & 20 deletions fern/pages/python_api/python-api-neighbors-hnsw.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ Parameters to build index for HNSW nearest neighbor search
| Name | Type | Description |
| --- | --- | --- |
| `hierarchy` | `string, default = "gpu" (optional)` | The hierarchy of the HNSW index.<br />Valid values are ["none", "cpu", "gpu"].<br />- "none": No hierarchy is built.<br />- "cpu": Hierarchy is built using CPU.<br />- "gpu": Hierarchy is built using GPU. |
| `ef_construction` | `int, default = 200 (optional)` | Maximum number of candidate list size used during construction when hierarchy is `cpu`. |
| `ef_construction` | `int, default = 200 (optional)` | Maximum candidate list size used during index construction. |
| `num_threads` | `int, default = 0 (optional)` | Number of CPU threads used to increase construction parallelism when hierarchy is `cpu` or `gpu`. When the value is 0, the number of threads is automatically determined to the maximum number of threads available.<br />NOTE: When hierarchy is `gpu`, while the majority of the work is done on the GPU, initialization of the HNSW index itself and some other work is parallelized with the help of CPU threads. |
| `M` | `int, default = 32 (optional)` | HNSW M parameter: number of bi-directional links per node (used when building with ACE). graph_degree = m * 2, intermediate_graph_degree = m * 3. |
| `M` | `int, default = 32 (optional)` | HNSW M parameter: number of bi-directional links per node. When the graph is built on the GPU, this parameter is used to derive the internal CAGRA graph build parameters. |
| `metric` | `string, default = "sqeuclidean" (optional)` | Distance metric to use.<br />Valid values: ["sqeuclidean", "inner_product"] |
| `ace_params` | `AceParams, default = None (optional)` | ACE parameters for building HNSW index using ACE algorithm. If set, enables the build() function to use ACE for index construction. |
| `ace_params` | `AceParams, default = None (optional)` | Explicit ACE parameters for out-of-core graph construction. When not set, the graph build algorithm is selected automatically. |

**Constructor**

Expand Down Expand Up @@ -200,20 +200,17 @@ def num_threads(self)
def build(IndexParams index_params, dataset, resources=None)
```

Build an HNSW index using the ACE (Augmented Core Extraction) algorithm.
Build an HNSW index from HNSW parameters.

ACE enables building HNSW indices for datasets too large to fit in GPU
memory by partitioning the dataset and building sub-indices for each
partition independently.

NOTE: This function requires `index_params.ace_params` to be set with
an instance of AceParams.
The graph is built on the GPU and converted to an HNSW index that can be
searched on the CPU. The graph build algorithm is selected automatically
unless explicit ACE parameters are provided.

**Parameters**

| Name | Type | Description |
| --- | --- | --- |
| `index_params` | `IndexParams` | Parameters for the HNSW index with ACE configuration. Must have `ace_params` set. |
| `index_params` | `IndexParams` | Parameters for the HNSW index. |
| `dataset` | `Host array interface compliant matrix shape (n_samples, dim)` | Supported dtype [float32, float16, int8, uint8] |
| `resources` | `cuvs.common.Resources, optional` | |

Expand All @@ -234,17 +231,9 @@ an instance of AceParams.
>>> dataset = np.random.random_sample((n_samples, n_features),
... dtype=np.float32)
>>>
>>> # Create ACE parameters
>>> ace_params = hnsw.AceParams(
... npartitions=4,
... use_disk=True,
... build_dir="/tmp/hnsw_ace_build"
... )
>>>
>>> # Create index parameters with ACE
>>> # Create HNSW index parameters
>>> index_params = hnsw.IndexParams(
... hierarchy="gpu",
... ace_params=ace_params,
... ef_construction=120,
... M=32,
... metric="sqeuclidean"
Expand Down
Loading
Loading