Skip to content

Commit 25b80d5

Browse files
Adding new examples for documenation. (#173)
Adding new examples to show how to build and use SVS when using the shared library enabling LVQ/LeanVec as well as the open-source only. --------- Co-authored-by: ethanglaser <[email protected]> Co-authored-by: Ethan Glaser <[email protected]>
1 parent 300f027 commit 25b80d5

File tree

6 files changed

+401
-5
lines changed

6 files changed

+401
-5
lines changed

examples/cpp/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@
1616

1717
# SVS C++ examples
1818

19+
To fully leverage SVS performance optimizations, see the [shared folder](./shared) for examples that utilize LVQ and LeanVec compression via the SVS shared or static library.
20+
1921
The examples provided here showcase SVS features. `vamana.cpp` shows search features; see the [getting started tutorial](https://intel.github.io/ScalableVectorSearch/start_cpp.html) for more details. `types.cpp` shows the types supported. `saveload.cpp` shows data structure saving and loading. `dispatcher.cpp` shows compile-time specialization with generic fallbacks.

examples/cpp/shared/CMakeLists.txt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ project(svs_shared_library_example
1919
)
2020

2121
# Other AVX versions can be found at https://github.com/intel/ScalableVectorSearch/releases.
22-
set(SVS_URL "https://github.com/intel/ScalableVectorSearch/releases/download/v0.0.8-dev/svs-shared-library-0.0.8-NIGHTLY-20250520-256-AVX512.tar.gz")
22+
set(SVS_URL "https://github.com/intel/ScalableVectorSearch/releases/download/v0.0.9/svs-shared-library-0.0.9.tar.gz")
2323

2424
include(FetchContent)
2525
FetchContent_Declare(
@@ -35,6 +35,15 @@ find_library(SVS_SHARED svs_shared_library)
3535
set(SVS_CXX_STANDARD 20)
3636
SET(CMAKE_CXX_FLAGS "-O3 -DNDEBUG -std=gnu++20 -march=native -mtune=native -Werror -Wall -Wextra -Wpedantic" )
3737

38-
add_executable(shared shared.cpp)
39-
target_link_libraries(shared PUBLIC ${SVS_SHARED} svs::svs)
38+
# Configure path to the datasets used in these examples
39+
set(DATA_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../data/test_dataset")
4040

41+
function(create_example_executable exe file)
42+
add_executable(${exe} ${file})
43+
target_compile_definitions(${exe} PRIVATE SVS_DATA_DIR="${DATA_DIRECTORY}")
44+
target_link_libraries(${exe} PUBLIC ${SVS_SHARED} svs::svs)
45+
endfunction()
46+
47+
create_example_executable(shared shared.cpp)
48+
create_example_executable(example_vamana_with_compression_lvq example_vamana_with_compression_lvq.cpp)
49+
create_example_executable(example_vamana_with_compression example_vamana_with_compression.cpp)

examples/cpp/shared/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
~ limitations under the License.
1515
-->
1616

17-
A simple example to use SVS shared library.
17+
These examples utilize LVQ and LeanVec interfaces which are available when linking to a SVS shared/static library, which are published with [releases](https://github.com/intel/ScalableVectorSearch/releases). Note that these examples will _not_ run after building the open source codebase without the shared/static library. These examples include:
18+
- [example_vamana_with_compression.cpp](./example_vamana_with_compression.cpp): Demonstrates building, searching, saving, and reloading an index with a LeanVec-compressed dataset.
19+
- [example_vamana_with_compression_lvq.cpp](./example_vamana_with_compression_lvq.cpp): Demonstrates building, searching, saving, and reloading an index with a LVQ-compressed dataset.
1820

19-
Follow the commands below to compile and use SVS shared library:
21+
See [CMakeLists.txt](./CMakeLists.txt) for details on linking to the SVS shared library and follow the commands below to compile and use the SVS shared library to run shared.cpp example:
2022

2123
```
2224
mkdir build
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2025 Intel Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// SVS
18+
#include "svs/core/recall.h"
19+
#include "svs/extensions/flat/leanvec.h"
20+
#include "svs/extensions/flat/lvq.h"
21+
#include "svs/extensions/vamana/leanvec.h"
22+
#include "svs/extensions/vamana/lvq.h"
23+
#include "svs/orchestrators/dynamic_vamana.h"
24+
#include "svs/orchestrators/exhaustive.h"
25+
#include "svs/orchestrators/vamana.h"
26+
27+
28+
int main() {
29+
// STEP 1: Compress Data with LeanVec, reducing dimensionality to leanvec_dim dimensions and using
30+
// 4 and 8 bits for primary and secondary levels respectively.
31+
//! [Compress data]
32+
const size_t num_threads = 4;
33+
size_t padding = 32;
34+
size_t leanvec_dim = 64;
35+
auto threadpool = svs::threads::as_threadpool(num_threads);
36+
auto loaded = svs::VectorDataLoader<float>(std::filesystem::path(SVS_DATA_DIR) / "data_f32.svs").load();
37+
auto data = svs::leanvec::LeanDataset<svs::leanvec::UsingLVQ<4>, svs::leanvec::UsingLVQ<8>, svs::Dynamic, svs::Dynamic>::reduce(
38+
loaded, std::nullopt, threadpool, padding, svs::lib::MaybeStatic<svs::Dynamic>(leanvec_dim)
39+
);
40+
//! [Compress data]
41+
42+
43+
// STEP 2: Build Vamana Index
44+
//! [Index Build]
45+
auto parameters = svs::index::vamana::VamanaBuildParameters{};
46+
svs::Vamana index = svs::Vamana::build<float>(parameters, data, svs::distance::DistanceL2(), num_threads);
47+
//! [Index Build]
48+
49+
// STEP 3: Search the Index
50+
//! [Perform Queries]
51+
const size_t search_window_size = 50;
52+
const size_t n_neighbors = 10;
53+
index.set_search_window_size(search_window_size);
54+
55+
auto queries = svs::load_data<float>(std::filesystem::path(SVS_DATA_DIR) / "queries_f32.fvecs");
56+
auto results = index.search(queries, n_neighbors);
57+
//! [Perform Queries]
58+
59+
//! [Recall]
60+
auto groundtruth = svs::load_data<int>(std::filesystem::path(SVS_DATA_DIR) / "groundtruth_euclidean.ivecs");
61+
double recall = svs::k_recall_at_n(groundtruth, results, n_neighbors, n_neighbors);
62+
63+
fmt::print("Recall@{} = {:.4f}\n", n_neighbors, recall);
64+
//! [Recall]
65+
66+
// STEP 4: Saving and reloading the index
67+
//! [Saving Loading]
68+
index.save("config", "graph", "data");
69+
index = svs::Vamana::assemble<float>(
70+
"config", svs::GraphLoader("graph"), svs::lib::load_from_disk<svs::leanvec::LeanDataset<svs::leanvec::UsingLVQ<4>, svs::leanvec::UsingLVQ<8>, svs::Dynamic, svs::Dynamic>>("data", padding), svs::distance::DistanceL2(), num_threads
71+
);
72+
//! [Saving Loading]
73+
index.set_search_window_size(search_window_size);
74+
recall = svs::k_recall_at_n(groundtruth, results, n_neighbors, n_neighbors);
75+
76+
fmt::print("Recall@{} after saving and reloading = {:.4f}\n", n_neighbors, recall);
77+
78+
79+
return 0;
80+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2025 Intel Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// SVS
18+
#include "svs/core/recall.h"
19+
#include "svs/extensions/flat/leanvec.h"
20+
#include "svs/extensions/flat/lvq.h"
21+
#include "svs/extensions/vamana/leanvec.h"
22+
#include "svs/extensions/vamana/lvq.h"
23+
#include "svs/orchestrators/dynamic_vamana.h"
24+
#include "svs/orchestrators/exhaustive.h"
25+
#include "svs/orchestrators/vamana.h"
26+
27+
28+
int main() {
29+
// STEP 1: Compress Data with LVQ
30+
//! [Compress data]
31+
size_t padding = 32;
32+
const size_t num_threads = 4;
33+
auto threadpool = svs::threads::as_threadpool(num_threads);
34+
auto loaded = svs::VectorDataLoader<float>(std::filesystem::path(SVS_DATA_DIR) / "data_f32.svs").load();
35+
auto data = svs::quantization::lvq::LVQDataset<4, 8>::compress(loaded, threadpool, padding);
36+
//! [Compress data]
37+
38+
// STEP 2: Build Vamana Index
39+
//! [Index Build]
40+
auto parameters = svs::index::vamana::VamanaBuildParameters{};
41+
svs::Vamana index = svs::Vamana::build<float>(parameters, data, svs::distance::DistanceL2(), num_threads);
42+
//! [Index Build]
43+
44+
// STEP 3: Search the Index
45+
//! [Perform Queries]
46+
const size_t search_window_size = 40;
47+
const size_t n_neighbors = 10;
48+
index.set_search_window_size(search_window_size);
49+
50+
auto queries = svs::load_data<float>(std::filesystem::path(SVS_DATA_DIR) / "queries_f32.fvecs");
51+
auto results = index.search(queries, n_neighbors);
52+
//! [Perform Queries]
53+
54+
//! [Recall]
55+
auto groundtruth = svs::load_data<int>(std::filesystem::path(SVS_DATA_DIR) / "groundtruth_euclidean.ivecs");
56+
double recall = svs::k_recall_at_n(groundtruth, results, n_neighbors, n_neighbors);
57+
58+
fmt::print("Recall@{} = {:.4f}\n", n_neighbors, recall);
59+
//! [Recall]
60+
61+
// STEP 4: Saving and reloading the index
62+
//! [Saving Loading]
63+
index.save("config", "graph", "data");
64+
index = svs::Vamana::assemble<float>(
65+
"config", svs::GraphLoader("graph"), svs::lib::load_from_disk<svs::quantization::lvq::LVQDataset<4, 8>>("data", padding), svs::distance::DistanceL2(), num_threads
66+
);
67+
//! [Saving Loading]
68+
index.set_search_window_size(search_window_size);
69+
recall = svs::k_recall_at_n(groundtruth, results, n_neighbors, n_neighbors);
70+
71+
fmt::print("Recall@{} after saving and reloading = {:.4f}\n", n_neighbors, recall);
72+
73+
74+
return 0;
75+
}

0 commit comments

Comments
 (0)