Repository: intel/ScalableVectorSearch
Pull request #96: feature!: verify and set default VamanaBuildParameters
Author: login: yuejiaointel
Created: 2025-03-18T01:05:23Z | Merged: 2025-03-28T19:47:05Z

BREAKING CHANGE: Removed the deprecated `num_threads` argument and added a `use_full_search_history` argument  in `VamanaBuildParameters` in Python bindings. This change ensures consistency between the Python API and the C++ implementation in `include/svs/index/vamana/build_params.h`.

Added default value setting and checking based on doc requirement, and added additional tests.

Pin CMake < 4 as a workaround until our dependencies require CMake >= 3.5.


Diff:
diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml
index 8bc8c14c8..aeea5a983 100644
--- a/bindings/python/pyproject.toml
+++ b/bindings/python/pyproject.toml
@@ -16,7 +16,7 @@
 requires = [
     "setuptools>=42",
     "scikit-build",
-    "cmake>=3.21",      # Keep in-sync with `CMakeLists.txt`
+    "cmake>=3.21, <4",      # Keep in-sync with `CMakeLists.txt`
     "numpy>=1.10.0, <2",    # Keep in-sync with `setup.py`
     "archspec>=0.2.0",  # Keep in-sync with `setup.py`
     "toml>=0.10.2",     # Keep in-sync with `setup.py` required for the tests
diff --git a/bindings/python/src/vamana.cpp b/bindings/python/src/vamana.cpp
index 9801c3060..603f50070 100644
--- a/bindings/python/src/vamana.cpp
+++ b/bindings/python/src/vamana.cpp
@@ -30,6 +30,7 @@
 #include "svs/lib/dispatcher.h"
 #include "svs/lib/float16.h"
 #include "svs/lib/meta.h"
+#include "svs/lib/preprocessor.h"
 #include "svs/orchestrators/vamana.h"
 
 // pybind
@@ -420,40 +421,22 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
+            py::arg("graph_max_degree") = svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT,
+            py::arg("window_size") = svs::VAMANA_WINDOW_SIZE_DEFAULT,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
+            py::arg("prune_to") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
+            py::arg("use_full_search_history") =
+                svs::VAMANA_USE_FULL_SEARCH_HISTORY_DEFAULT,
             R"(
             Construct a new instance from keyword arguments.
 
@@ -462,6 +445,7 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for MIP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
                     of a larger memory footprint.
@@ -470,10 +454,15 @@ void wrap(py::module& m) {
                     longer construction time. Should be larger than `graph_max_degree`.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is ``graph_max_degree`` * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
-                    `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    ``graph_max_degree`` will yield faster index building times. Default:
+                    ` `graph_max_degree`` - 4 if
+                    ``graph_max_degree`` is at least 16, otherwise ``graph_max_degree``.
+                use_full_search_history: When true, uses the full search history during
+                    graph construction, which can improve graph quality at the expense of
+                    additional memory and potentially longer build times.
             )"
         )
         .def_readwrite("alpha", &svs::index::vamana::VamanaBuildParameters::alpha)
@@ -557,4 +546,4 @@ overwritten when saving the index to this directory.
     )"
     );
 }
-} // namespace svs::python::vamana
+} // namespace svs::python::vamana
\ No newline at end of file
diff --git a/bindings/python/tests/test_dynamic_vamana.py b/bindings/python/tests/test_dynamic_vamana.py
index 7fa486408..84d78217c 100644
--- a/bindings/python/tests/test_dynamic_vamana.py
+++ b/bindings/python/tests/test_dynamic_vamana.py
@@ -98,7 +98,7 @@ def test_loop(self):
         # here, we set an expected mid-point for the recall and allow it to wander up and
         # down by a little.
         expected_recall = 0.845
-        expected_recall_delta = 0.03
+        expected_recall_delta = 0.05
 
         reference = ReferenceDataset(num_threads = num_threads)
         data, ids = reference.new_ids(5000)
diff --git a/bindings/python/tests/test_vamana.py b/bindings/python/tests/test_vamana.py
index 763afe883..8b288564f 100644
--- a/bindings/python/tests/test_vamana.py
+++ b/bindings/python/tests/test_vamana.py
@@ -281,13 +281,6 @@ def test_basic(self):
             self._test_basic(loader, matcher, first_iter = first_iter)
             first_iter = False
 
-    def test_deprecation(self):
-        with warnings.catch_warnings(record = True) as w:
-            p = svs.VamanaBuildParameters(num_threads = 1)
-            self.assertTrue(len(w) == 1)
-            self.assertTrue(issubclass(w[0].category, DeprecationWarning))
-            self.assertTrue("VamanaBuildParameters" in str(w[0].message))
-
     def _groundtruth_map(self):
         return {
             svs.DistanceType.L2: test_groundtruth_l2,
diff --git a/include/svs/index/vamana/build_params.h b/include/svs/index/vamana/build_params.h
index 119591341..65b5039c3 100644
--- a/include/svs/index/vamana/build_params.h
+++ b/include/svs/index/vamana/build_params.h
@@ -17,6 +17,7 @@
 #pragma once
 
 // svs
+#include "svs/lib/preprocessor.h"
 #include "svs/lib/saveload.h"
 
 // stl
@@ -44,33 +45,33 @@ struct VamanaBuildParameters {
         , use_full_search_history{use_full_search_history_} {}
 
     /// The pruning parameter.
-    float alpha;
+    float alpha = svs::FLOAT_PLACEHOLDER;
 
     /// The maximum degree in the graph. A higher max degree may yield a higher quality
     /// graph in terms of recall for performance, but the memory footprint of the graph is
     /// directly proportional to the maximum degree.
-    size_t graph_max_degree;
+    size_t graph_max_degree = svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT;
 
     /// The search window size to use during graph construction. A higher search window
     /// size will yield a higher quality graph since more overall vertices are considered,
     /// but will increase construction time.
-    size_t window_size;
+    size_t window_size = svs::VAMANA_WINDOW_SIZE_DEFAULT;
 
     /// Set a limit on the number of neighbors considered during pruning. In practice, set
     /// this to a high number (at least 5 times greater than the window_size) and forget
     /// about it.
-    size_t max_candidate_pool_size;
+    size_t max_candidate_pool_size = svs::UNSIGNED_INTEGER_PLACEHOLDER;
 
     /// This is the amount that candidates will be pruned to after certain pruning
     /// procedures. Setting this to less than ``graph_max_degree`` can result in significant
     /// speedups in index building.
-    size_t prune_to;
+    size_t prune_to = svs::UNSIGNED_INTEGER_PLACEHOLDER;
 
     /// When building, either the contents of the search buffer can be used or the entire
     /// search history can be used.
     ///
     /// The latter case may yield a slightly better graph as the cost of more search time.
-    bool use_full_search_history = true;
+    bool use_full_search_history = svs::VAMANA_USE_FULL_SEARCH_HISTORY_DEFAULT;
 
     ///// Comparison
     friend bool
@@ -129,4 +130,4 @@ struct VamanaBuildParameters {
         );
     }
 };
-} // namespace svs::index::vamana
+} // namespace svs::index::vamana
\ No newline at end of file
diff --git a/include/svs/index/vamana/dynamic_index.h b/include/svs/index/vamana/dynamic_index.h
index 6a37778b1..39891edc4 100644
--- a/include/svs/index/vamana/dynamic_index.h
+++ b/include/svs/index/vamana/dynamic_index.h
@@ -38,6 +38,7 @@
 #include "svs/index/vamana/index.h"
 #include "svs/index/vamana/vamana_build.h"
 #include "svs/lib/boundscheck.h"
+#include "svs/lib/preprocessor.h"
 #include "svs/lib/threads.h"
 
 namespace svs::index::vamana {
@@ -157,6 +158,9 @@ class MutableVamanaIndex {
     float alpha_ = 1.2;
     bool use_full_search_history_ = true;
 
+    // Construction parameters
+    VamanaBuildParameters build_parameters_{};
+
     // SVS logger for per index logging
     svs::logging::logger_ptr logger_;
 
@@ -210,12 +214,19 @@ class MutableVamanaIndex {
         , distance_(std::move(distance_function))
         , threadpool_(threads::as_threadpool(std::move(threadpool_proto)))
         , search_parameters_(vamana::construct_default_search_parameters(data_))
-        , construction_window_size_(parameters.window_size)
-        , max_candidates_(parameters.max_candidate_pool_size)
-        , prune_to_(parameters.prune_to)
-        , alpha_(parameters.alpha)
-        , use_full_search_history_{parameters.use_full_search_history}
+        , build_parameters_(parameters)
         , logger_{std::move(logger)} {
+        // Verify and set defaults directly on the input parameters
+        verify_and_set_default_index_parameters(build_parameters_, distance_function);
+
+        // Set graph again as verify function might change graph_max_degree parameter
+        graph_ = Graph{data_.size(), build_parameters_.graph_max_degree};
+        construction_window_size_ = build_parameters_.window_size;
+        max_candidates_ = build_parameters_.max_candidate_pool_size;
+        prune_to_ = build_parameters_.prune_to;
+        alpha_ = build_parameters_.alpha;
+        use_full_search_history_ = build_parameters_.use_full_search_history;
+
         // Setup the initial translation of external to internal ids.
         translator_.insert(external_ids, threads::UnitRange<Idx>(0, external_ids.size()));
 
@@ -227,10 +238,12 @@ class MutableVamanaIndex {
         auto prefetch_parameters =
             GreedySearchPrefetchParameters{sp.prefetch_lookahead_, sp.prefetch_step_};
         auto builder = VamanaBuilder(
-            graph_, data_, distance_, parameters, threadpool_, prefetch_parameters
+            graph_, data_, distance_, build_parameters_, threadpool_, prefetch_parameters
         );
         builder.construct(1.0f, entry_point_[0], logging::Level::Info, logger_);
-        builder.construct(parameters.alpha, entry_point_[0], logging::Level::Info, logger_);
+        builder.construct(
+            build_parameters_.alpha, entry_point_[0], logging::Level::Info, logger_
+        );
     }
 
     /// @brief Post re-load constructor.
@@ -1346,4 +1359,4 @@ auto auto_dynamic_assemble(
         std::move(logger)};
 }
 
-} // namespace svs::index::vamana
+} // namespace svs::index::vamana
\ No newline at end of file
diff --git a/include/svs/index/vamana/index.h b/include/svs/index/vamana/index.h
index a50ce11d6..1ee96cd5d 100644
--- a/include/svs/index/vamana/index.h
+++ b/include/svs/index/vamana/index.h
@@ -404,19 +404,22 @@ class VamanaIndex {
         if (graph_.n_nodes() != data_.size()) {
             throw ANNEXCEPTION("Wrong sizes!");
         }
-
         build_parameters_ = parameters;
+        // verify the parameters before set local var
+        verify_and_set_default_index_parameters(build_parameters_, distance_function);
         auto builder = VamanaBuilder(
             graph_,
             data_,
             distance_,
-            parameters,
+            build_parameters_,
             threadpool_,
             extensions::estimate_prefetch_parameters(data_)
         );
 
         builder.construct(1.0F, entry_point_[0], logging::Level::Info, logger);
-        builder.construct(parameters.alpha, entry_point_[0], logging::Level::Info, logger);
+        builder.construct(
+            build_parameters_.alpha, entry_point_[0], logging::Level::Info, logger
+        );
     }
 
     /// @brief Getter method for logger
@@ -896,10 +899,13 @@ auto auto_build(
     auto entry_point = extensions::compute_entry_point(data, threadpool);
 
     // Default graph.
-    auto graph = default_graph(data.size(), parameters.graph_max_degree, graph_allocator);
+    auto verified_parameters = parameters;
+    verify_and_set_default_index_parameters(verified_parameters, distance);
+    auto graph =
+        default_graph(data.size(), verified_parameters.graph_max_degree, graph_allocator);
     using I = typename decltype(graph)::index_type;
     return VamanaIndex{
-        parameters,
+        verified_parameters,
         std::move(graph),
         std::move(data),
         lib::narrow<I>(entry_point),
@@ -959,4 +965,57 @@ auto auto_assemble(
     index.apply(config);
     return index;
 }
+
+/// @brief Verify parameters and set defaults if needed
+template <typename Dist>
+void verify_and_set_default_index_parameters(
+    VamanaBuildParameters& parameters, Dist distance_function
+) {
+    // Set default values
+    if (parameters.max_candidate_pool_size == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        parameters.max_candidate_pool_size = 2 * parameters.graph_max_degree;
+    }
+
+    if (parameters.prune_to == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        if (parameters.graph_max_degree >= 16) {
+            parameters.prune_to = parameters.graph_max_degree - 4;
+        } else {
+            parameters.prune_to = parameters.graph_max_degree;
+        }
+    }
+
+    // Check supported distance type using std::is_same type trait
+    using dist_type = std::decay_t<decltype(distance_function)>;
+    // Create type flags for each distance type
+    constexpr bool is_L2 = std::is_same_v<dist_type, svs::distance::DistanceL2>;
+    constexpr bool is_IP = std::is_same_v<dist_type, svs::distance::DistanceIP>;
+    constexpr bool is_Cosine =
+        std::is_same_v<dist_type, svs::distance::DistanceCosineSimilarity>;
+
+    // Handle alpha based on distance type
+    if constexpr (is_L2) {
+        if (parameters.alpha == svs::FLOAT_PLACEHOLDER) {
+            parameters.alpha = svs::VAMANA_ALPHA_MINIMIZE_DEFAULT;
+        } else if (parameters.alpha < 1.0f) {
+            // Check User set values
+            throw std::invalid_argument("For L2 distance, alpha must be >= 1.0");
+        }
+    } else if constexpr (is_IP || is_Cosine) {
+        if (parameters.alpha == svs::FLOAT_PLACEHOLDER) {
+            parameters.alpha = svs::VAMANA_ALPHA_MAXIMIZE_DEFAULT;
+        } else if (parameters.alpha > 1.0f) {
+            // Check User set values
+            throw std::invalid_argument("For MIP/Cosine distance, alpha must be <= 1.0");
+        } else if (parameters.alpha <= 0.0f) {
+            throw std::invalid_argument("alpha must be > 0");
+        }
+    } else {
+        throw std::invalid_argument("Unsupported distance type");
+    }
+
+    // Check prune_to <= graph_max_degree
+    if (parameters.prune_to > parameters.graph_max_degree) {
+        throw std::invalid_argument("prune_to must be <= graph_max_degree");
+    }
+}
 } // namespace svs::index::vamana
diff --git a/include/svs/lib/preprocessor.h b/include/svs/lib/preprocessor.h
index f1765cde6..e3a1900db 100644
--- a/include/svs/lib/preprocessor.h
+++ b/include/svs/lib/preprocessor.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <cstddef>
+#include <limits>
+
 namespace svs::preprocessor::detail {
 
 // consteval functions for working with preprocessor defines.
@@ -159,3 +162,14 @@ inline constexpr bool have_avx512_avx2 = true;
 #endif
 
 } // namespace svs::arch
+
+namespace svs {
+// Maximum values used as default initializers
+inline constexpr size_t UNSIGNED_INTEGER_PLACEHOLDER = std::numeric_limits<size_t>::max();
+inline constexpr float FLOAT_PLACEHOLDER = std::numeric_limits<float>::max();
+inline constexpr float VAMANA_GRAPH_MAX_DEGREE_DEFAULT = 32;
+inline constexpr float VAMANA_WINDOW_SIZE_DEFAULT = 64;
+inline constexpr bool VAMANA_USE_FULL_SEARCH_HISTORY_DEFAULT = true;
+inline constexpr float VAMANA_ALPHA_MINIMIZE_DEFAULT = 1.2;
+inline constexpr float VAMANA_ALPHA_MAXIMIZE_DEFAULT = 0.95;
+} // namespace svs
\ No newline at end of file
diff --git a/tests/svs/index/vamana/dynamic_index_2.cpp b/tests/svs/index/vamana/dynamic_index_2.cpp
index a3acb7f04..f09c2c1e3 100644
--- a/tests/svs/index/vamana/dynamic_index_2.cpp
+++ b/tests/svs/index/vamana/dynamic_index_2.cpp
@@ -19,6 +19,7 @@
 #include "svs/core/recall.h"
 #include "svs/index/flat/flat.h"
 #include "svs/index/vamana/dynamic_index.h"
+#include "svs/lib/preprocessor.h"
 #include "svs/lib/timing.h"
 
 #include "svs/misc/dynamic_helper.h"
@@ -476,4 +477,144 @@ CATCH_TEST_CASE("Dynamic MutableVamanaIndex Default Logger Test", "[logging]") {
     // Verify that the default logger is used
     auto default_logger = svs::logging::get();
     CATCH_REQUIRE(index.get_logger() == default_logger);
+}
+
+CATCH_TEST_CASE("Dynamic Vamana Index Default Parameters", "[parameter][vamana]") {
+    using Catch::Approx;
+    std::filesystem::path data_path = test_dataset::data_svs_file();
+
+    CATCH_SECTION("L2 Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+
+        // Get IDs for all points in the dataset
+        std::vector<size_t> indices(data_loader.size());
+        std::iota(indices.begin(), indices.end(), 0);
+
+        // Build dynamic index with L2 distance
+        auto index = svs::index::vamana::MutableVamanaIndex(
+            build_params, std::move(data_loader), indices, svs::distance::DistanceL2(), 2
+        );
+
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MINIMIZE_DEFAULT));
+    }
+
+    CATCH_SECTION("MIP Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+
+        // Get IDs for all points in the dataset
+        std::vector<size_t> indices(data_loader.size());
+        std::iota(indices.begin(), indices.end(), 0);
+
+        // Build dynamic index with MIP distance
+        auto index = svs::index::vamana::MutableVamanaIndex(
+            build_params, std::move(data_loader), indices, svs::distance::DistanceIP(), 2
+        );
+
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MAXIMIZE_DEFAULT));
+    }
+
+    CATCH_SECTION("Invalid Alpha for L2") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 0.8f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+
+        // Get IDs for all points in the dataset
+        std::vector<size_t> indices(data_loader.size());
+        std::iota(indices.begin(), indices.end(), 0);
+
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::index::vamana::MutableVamanaIndex(
+                build_params,
+                std::move(data_loader),
+                indices,
+                svs::distance::DistanceL2(),
+                2
+            ),
+            "For L2 distance, alpha must be >= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid Alpha for MIP") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 1.2f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+
+        // Get IDs for all points in the dataset
+        std::vector<size_t> indices(data_loader.size());
+        std::iota(indices.begin(), indices.end(), 0);
+
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::index::vamana::MutableVamanaIndex(
+                build_params,
+                std::move(data_loader),
+                indices,
+                svs::distance::DistanceIP(),
+                2
+            ),
+            "For MIP/Cosine distance, alpha must be <= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid prune_to > graph_max_degree") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.prune_to = build_params.graph_max_degree + 10;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+
+        // Get IDs for all points in the dataset
+        std::vector<size_t> indices(data_loader.size());
+        std::iota(indices.begin(), indices.end(), 0);
+
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::index::vamana::MutableVamanaIndex(
+                build_params,
+                std::move(data_loader),
+                indices,
+                svs::distance::DistanceL2(),
+                2
+            ),
+            "prune_to must be <= graph_max_degree"
+        );
+    }
+
+    CATCH_SECTION("L2 Distance Empty Params") {
+        svs::index::vamana::VamanaBuildParameters params;
+        std::vector<float> data(32);
+        for (size_t i = 0; i < data.size(); i++) {
+            data[i] = static_cast<float>(i + 1);
+        }
+        auto data_view = svs::data::SimpleDataView<float>(data.data(), 8, 4);
+        std::vector<size_t> indices = {0, 1, 2, 3, 4, 5, 6, 7};
+        auto index = svs::index::vamana::MutableVamanaIndex(
+            params, std::move(data_view), indices, svs::distance::DistanceL2(), 1
+        );
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MINIMIZE_DEFAULT));
+        CATCH_REQUIRE(index.get_graph_max_degree() == svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT);
+        CATCH_REQUIRE(index.get_prune_to() == svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT - 4);
+        CATCH_REQUIRE(
+            index.get_construction_window_size() == svs::VAMANA_WINDOW_SIZE_DEFAULT
+        );
+        CATCH_REQUIRE(
+            index.get_max_candidates() == 2 * svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT
+        );
+        CATCH_REQUIRE(
+            index.get_full_search_history() == svs::VAMANA_USE_FULL_SEARCH_HISTORY_DEFAULT
+        );
+    }
 }
\ No newline at end of file
diff --git a/tests/svs/index/vamana/index.cpp b/tests/svs/index/vamana/index.cpp
index cd5492996..6ceba9a1d 100644
--- a/tests/svs/index/vamana/index.cpp
+++ b/tests/svs/index/vamana/index.cpp
@@ -16,12 +16,26 @@
 
 // Header under test
 #include "svs/index/vamana/index.h"
+
+// Logging
 #include "spdlog/sinks/callback_sink.h"
 #include "svs/core/logging.h"
 
+// svs
+#include "svs/index/vamana/build_params.h"
+#include "svs/lib/preprocessor.h"
+
 // catch2
 #include "catch2/catch_test_macros.hpp"
+#include <catch2/catch_approx.hpp>
 
+// tests
+#include "tests/utils/test_dataset.h"
+#include "tests/utils/utils.h"
+#include "tests/utils/vamana_reference.h"
+
+// svsbenchmark
+#include "svs-benchmark/benchmark.h"
 // stl
 #include <string_view>
 
@@ -150,4 +164,86 @@ CATCH_TEST_CASE("Static VamanaIndex Per-Index Logging", "[logging]") {
     // Verify the internal log messages
     CATCH_REQUIRE(captured_logs[0].find("Number of syncs:") != std::string::npos);
     CATCH_REQUIRE(captured_logs[1].find("Batch Size:") != std::string::npos);
+}
+
+CATCH_TEST_CASE("Vamana Index Default Parameters", "[parameter][vamana]") {
+    using Catch::Approx;
+    std::filesystem::path data_path = test_dataset::data_svs_file();
+
+    CATCH_SECTION("L2 Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MINIMIZE_DEFAULT));
+    }
+
+    CATCH_SECTION("MIP Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::MIP);
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MAXIMIZE_DEFAULT));
+    }
+
+    CATCH_SECTION("Invalid Alpha for L2") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 0.8f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "For L2 distance, alpha must be >= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid Alpha for MIP") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 1.2f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::MIP),
+            "For MIP/Cosine distance, alpha must be <= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid prune_to > graph_max_degree") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.prune_to = build_params.graph_max_degree + 10;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "prune_to must be <= graph_max_degree"
+        );
+    }
+
+    CATCH_SECTION("L2 Distance Empty Params") {
+        svs::index::vamana::VamanaBuildParameters empty_params;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(empty_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(svs::VAMANA_ALPHA_MINIMIZE_DEFAULT));
+        CATCH_REQUIRE(index.get_graph_max_degree() == svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT);
+        CATCH_REQUIRE(index.get_prune_to() == svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT - 4);
+        CATCH_REQUIRE(
+            index.get_construction_window_size() == svs::VAMANA_WINDOW_SIZE_DEFAULT
+        );
+        CATCH_REQUIRE(
+            index.get_max_candidates() == 2 * svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT
+        );
+        CATCH_REQUIRE(
+            index.get_full_search_history() == svs::VAMANA_USE_FULL_SEARCH_HISTORY_DEFAULT
+        );
+    }
 }
\ No newline at end of file


Reviews:
user: login: ibhati
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:58:42Z
user: login: mihaic
body: Good work, @yuejiaointel! I look forward to not having to care about the default value of `alpha`. :) I think we can make a couple of improvements. Please see my suggestions.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-21T21:24:29Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:54:17Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:54:46Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:55:31Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:55:54Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:56:30Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:56:44Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:56:53Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T04:56:58Z
user: login: mihaic
body: Thank you for accommodating my suggestions. I think the code looks good now. We should also update the docs.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T17:29:02Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T21:56:41Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T21:56:52Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T21:57:10Z
user: login: ibhati
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T16:10:14Z
user: login: ibhati
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T16:10:56Z
user: login: ibhati
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T16:12:08Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T16:29:09Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T18:44:58Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T18:45:04Z
user: login: ibhati
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-27T20:34:43Z
user: login: dian-lun-lin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T21:10:34Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T21:25:27Z
user: login: dian-lun-lin
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T22:16:24Z
user: login: mihaic
body: The signature for `VamanaBuildParameters` looks good in the docs! That was my main concern. I am leaving suggestions for removing duplication like the repetition of defaults for the defaults that are shown in the signature and for reStructuredText (vs Markdown) formatting.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-28T00:38:46Z
user: login: yuejiaointel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T00:52:49Z
user: login: mihaic
body: Thanks a lot for your contribution (and for your patience), @yuejiaointel! SVS users will benefit greatly from the new defaults.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-28T00:54:20Z

Review comments:
diff_hunk: @@ -281,12 +281,12 @@ def test_basic(self):
             self._test_basic(loader, matcher, first_iter = first_iter)
             first_iter = False
 
-    def test_deprecation(self):
-        with warnings.catch_warnings(record = True) as w:
-            p = svs.VamanaBuildParameters(num_threads = 1)
-            self.assertTrue(len(w) == 1)
-            self.assertTrue(issubclass(w[0].category, DeprecationWarning))
-            self.assertTrue("VamanaBuildParameters" in str(w[0].message))
+    # def test_deprecation(self):
+    #     with warnings.catch_warnings(record = True) as w:
+    #         p = svs.VamanaBuildParameters(num_threads = 1)
+    #         self.assertTrue(len(w) == 1)
+    #         self.assertTrue(issubclass(w[0].category, DeprecationWarning))
+    #         self.assertTrue("VamanaBuildParameters" in str(w[0].message))
path: bindings/python/tests/test_vamana.py
user: login: mihaic
body: If there is no particular reason to keep this commented code, let's remove it.
```suggestion
```
created_at: 2025-03-21T18:10:23Z
author_association: MEMBER
diff_hunk: @@ -959,4 +962,74 @@ auto auto_assemble(
     index.apply(config);
     return index;
 }
+
+/// @brief Verify parameters and set defaults if needed
+template <typename Dist>
+void verify_or_set_default_index_parameters(
+    VamanaBuildParameters& parameters, Dist distance_function
+) {
+    // Set default values
+    if (parameters.graph_max_degree == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.graph_max_degree = 32;
+    }
+
+    if (parameters.window_size == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.window_size = 64;
+    }
+
+    if (parameters.max_candidate_pool_size == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.max_candidate_pool_size = 2 * parameters.graph_max_degree;
+    }
+
+    if (parameters.prune_to == svs::UNSIGNED_INTEGER_MAX) {
+        if (parameters.graph_max_degree >= 16) {
+            parameters.prune_to = parameters.graph_max_degree - 4;
+        } else {
+            parameters.prune_to = parameters.graph_max_degree;
+        }
+    }
+
+    // Check supported distance type using std::is_same type trait
+    using dist_type = std::decay_t<decltype(distance_function)>;
+    // Create type flags for each distance type
+    constexpr bool is_L2 = std::is_same_v<dist_type, svs::distance::DistanceL2>;
+    constexpr bool is_IP = std::is_same_v<dist_type, svs::distance::DistanceIP>;
+    constexpr bool is_Cosine =
+        std::is_same_v<dist_type, svs::distance::DistanceCosineSimilarity>;
+
+    if (parameters.alpha == svs::FLOAT_MAX) {
+        // Check if it's a supported distance type
+        if (is_L2) {
+            parameters.alpha = 1.2f;
+        } else if (is_IP || is_Cosine) {
+            parameters.alpha = 0.95f;
+        } else {
+            throw std::invalid_argument("Unsupported distance type");
+        }
+    }
+
+    // Check User set values
+    // Validate number parameters are positive
+    if (parameters.alpha < 0.0f) {
path: include/svs/index/vamana/index.h
user: login: ibhati
body: ```suggestion
    if (parameters.alpha <= 0.0f) {
```
created_at: 2025-03-21T19:44:20Z
author_association: MEMBER
diff_hunk: @@ -16,10 +16,95 @@
 
 // SVS
 #include "svs/orchestrators/vamana.h"
+#include "svs/index/vamana/build_params.h"
 
 // Catch2
 #include "catch2/catch_test_macros.hpp"
+#include <catch2/catch_approx.hpp>
+
+// svsbenchmark
+#include "svs-benchmark/benchmark.h"
+
+// tests
+#include "tests/utils/test_dataset.h"
+#include "tests/utils/utils.h"
+#include "tests/utils/vamana_reference.h"
 
 CATCH_TEST_CASE("Vamana Index", "[managers][vamana]") {
     // Todo?
 }
+CATCH_TEST_CASE("Vamana Index Default Parameters", "[managers][vamana]") {
+    using Catch::Approx;
+    std::filesystem::path data_path = test_dataset::data_svs_file();
+
+    CATCH_SECTION("L2 Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(1.2f));
+    }
+
+    CATCH_SECTION("MIP Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::MIP);
+        CATCH_REQUIRE(index.get_alpha() == Approx(0.95f));
+    }
+
+    CATCH_SECTION("Invalid Alpha for L2") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 0.8f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "For L2 distance, alpha must be >= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid Alpha for MIP") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 1.2f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::MIP),
+            "For MIP/Cosine distance, alpha must be <= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid prune_to > graph_max_degree") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.prune_to = build_params.graph_max_degree + 10;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "prune_to must be <= graph_max_degree"
+        );
+    }
+
+    CATCH_SECTION("L2 Distance Empty Params") {
+        svs::index::vamana::VamanaBuildParameters empty_params;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(empty_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(1.2f));
+        CATCH_REQUIRE(index.get_graph_max_degree() == 32);
+        CATCH_REQUIRE(index.get_prune_to() == 28);
+        CATCH_REQUIRE(index.get_construction_window_size() == 64);
+        CATCH_REQUIRE(index.get_max_candidates() == 64);
+        CATCH_REQUIRE(index.get_full_search_history() == true);
+    }
+}
path: tests/svs/orchestrators/vamana.cpp
user: login: ibhati
body: I think these tests should go to svs/index/vamana/index.cpp where the logic is implemented. Also, can we add similar tests for dynamic_index?
created_at: 2025-03-21T19:54:19Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: It should be completely clear that we are using a placeholder value, so let's just use "placeholder" in the name. Please rename everywhere.
```suggestion
            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
```
created_at: 2025-03-21T20:43:27Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: We are not setting `graph_max_degree` based on other parameters. The default is always 32. Let's leave it as 32 so users immediately see what the default is.
```suggestion
            py::arg("graph_max_degree") = 32,
```
created_at: 2025-03-21T20:44:03Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: Same as `graph_max_degree`.
```suggestion
            py::arg("window_size") = 64,
```
created_at: 2025-03-21T20:47:39Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: Same as alpha.
```suggestion
            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
```
created_at: 2025-03-21T20:48:47Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("prune_to") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
            py::arg("prune_to") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
```
created_at: 2025-03-21T20:49:01Z
author_association: MEMBER
diff_hunk: @@ -959,4 +962,74 @@ auto auto_assemble(
     index.apply(config);
     return index;
 }
+
+/// @brief Verify parameters and set defaults if needed
+template <typename Dist>
+void verify_or_set_default_index_parameters(
+    VamanaBuildParameters& parameters, Dist distance_function
+) {
+    // Set default values
+    if (parameters.graph_max_degree == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.graph_max_degree = 32;
+    }
+
+    if (parameters.window_size == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.window_size = 64;
+    }
+
+    if (parameters.max_candidate_pool_size == svs::UNSIGNED_INTEGER_MAX) {
+        parameters.max_candidate_pool_size = 2 * parameters.graph_max_degree;
+    }
+
+    if (parameters.prune_to == svs::UNSIGNED_INTEGER_MAX) {
+        if (parameters.graph_max_degree >= 16) {
+            parameters.prune_to = parameters.graph_max_degree - 4;
+        } else {
+            parameters.prune_to = parameters.graph_max_degree;
+        }
+    }
+
+    // Check supported distance type using std::is_same type trait
+    using dist_type = std::decay_t<decltype(distance_function)>;
+    // Create type flags for each distance type
+    constexpr bool is_L2 = std::is_same_v<dist_type, svs::distance::DistanceL2>;
+    constexpr bool is_IP = std::is_same_v<dist_type, svs::distance::DistanceIP>;
+    constexpr bool is_Cosine =
+        std::is_same_v<dist_type, svs::distance::DistanceCosineSimilarity>;
+
+    if (parameters.alpha == svs::FLOAT_MAX) {
+        // Check if it's a supported distance type
+        if (is_L2) {
+            parameters.alpha = 1.2f;
+        } else if (is_IP || is_Cosine) {
+            parameters.alpha = 0.95f;
+        } else {
+            throw std::invalid_argument("Unsupported distance type");
+        }
+    }
+
+    // Check User set values
+    // Validate number parameters are positive
+    if (parameters.alpha < 0.0f) {
path: include/svs/index/vamana/index.h
user: login: yuejiaointel
body: Good catch, fixed!
created_at: 2025-03-24T04:54:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -16,10 +16,95 @@
 
 // SVS
 #include "svs/orchestrators/vamana.h"
+#include "svs/index/vamana/build_params.h"
 
 // Catch2
 #include "catch2/catch_test_macros.hpp"
+#include <catch2/catch_approx.hpp>
+
+// svsbenchmark
+#include "svs-benchmark/benchmark.h"
+
+// tests
+#include "tests/utils/test_dataset.h"
+#include "tests/utils/utils.h"
+#include "tests/utils/vamana_reference.h"
 
 CATCH_TEST_CASE("Vamana Index", "[managers][vamana]") {
     // Todo?
 }
+CATCH_TEST_CASE("Vamana Index Default Parameters", "[managers][vamana]") {
+    using Catch::Approx;
+    std::filesystem::path data_path = test_dataset::data_svs_file();
+
+    CATCH_SECTION("L2 Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(1.2f));
+    }
+
+    CATCH_SECTION("MIP Distance Defaults") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(build_params, data_loader, svs::MIP);
+        CATCH_REQUIRE(index.get_alpha() == Approx(0.95f));
+    }
+
+    CATCH_SECTION("Invalid Alpha for L2") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 0.8f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "For L2 distance, alpha must be >= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid Alpha for MIP") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::MIP, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.alpha = 1.2f;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::MIP),
+            "For MIP/Cosine distance, alpha must be <= 1.0"
+        );
+    }
+
+    CATCH_SECTION("Invalid prune_to > graph_max_degree") {
+        auto expected_result = test_dataset::vamana::expected_build_results(
+            svs::L2, svsbenchmark::Uncompressed(svs::DataType::float32)
+        );
+        auto build_params = expected_result.build_parameters_.value();
+        build_params.prune_to = build_params.graph_max_degree + 10;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        CATCH_REQUIRE_THROWS_WITH(
+            svs::Vamana::build<float>(build_params, data_loader, svs::L2),
+            "prune_to must be <= graph_max_degree"
+        );
+    }
+
+    CATCH_SECTION("L2 Distance Empty Params") {
+        svs::index::vamana::VamanaBuildParameters empty_params;
+        auto data_loader = svs::data::SimpleData<float>::load(data_path);
+        svs::Vamana index = svs::Vamana::build<float>(empty_params, data_loader, svs::L2);
+        CATCH_REQUIRE(index.get_alpha() == Approx(1.2f));
+        CATCH_REQUIRE(index.get_graph_max_degree() == 32);
+        CATCH_REQUIRE(index.get_prune_to() == 28);
+        CATCH_REQUIRE(index.get_construction_window_size() == 64);
+        CATCH_REQUIRE(index.get_max_candidates() == 64);
+        CATCH_REQUIRE(index.get_full_search_history() == true);
+    }
+}
path: tests/svs/orchestrators/vamana.cpp
user: login: yuejiaointel
body: Good idea, moved and added similar tests in dynamic_index_2.cpp
created_at: 2025-03-24T04:54:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -281,12 +281,12 @@ def test_basic(self):
             self._test_basic(loader, matcher, first_iter = first_iter)
             first_iter = False
 
-    def test_deprecation(self):
-        with warnings.catch_warnings(record = True) as w:
-            p = svs.VamanaBuildParameters(num_threads = 1)
-            self.assertTrue(len(w) == 1)
-            self.assertTrue(issubclass(w[0].category, DeprecationWarning))
-            self.assertTrue("VamanaBuildParameters" in str(w[0].message))
+    # def test_deprecation(self):
+    #     with warnings.catch_warnings(record = True) as w:
+    #         p = svs.VamanaBuildParameters(num_threads = 1)
+    #         self.assertTrue(len(w) == 1)
+    #         self.assertTrue(issubclass(w[0].category, DeprecationWarning))
+    #         self.assertTrue("VamanaBuildParameters" in str(w[0].message))
path: bindings/python/tests/test_vamana.py
user: login: yuejiaointel
body: Thx, removed, these are no longer needed
created_at: 2025-03-24T04:55:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, renamed!
created_at: 2025-03-24T04:55:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, renamed it to be GRAPH_MAX_DEGREE_DEFAULT with value 32
created_at: 2025-03-24T04:56:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: 

Thx, renamed it to be WINDOW_SIZE_DEFAULT with value 64

created_at: 2025-03-24T04:56:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, renamed!
created_at: 2025-03-24T04:56:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_MAX,
+            py::arg("graph_max_degree") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("window_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_MAX,
+            py::arg("prune_to") = svs::UNSIGNED_INTEGER_MAX,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: 

Thx, renamed!

created_at: 2025-03-24T04:56:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -159,3 +162,12 @@ inline constexpr bool have_avx512_avx2 = true;
 #endif
 
 } // namespace svs::arch
+
+namespace svs {
+// Maximum values used as default initializers
+inline constexpr size_t UNSIGNED_INTEGER_PLACEHOLDER = std::numeric_limits<size_t>::max();
+inline constexpr float FLOAT_PLACEHOLDER = std::numeric_limits<float>::max();
+inline constexpr float GRAPH_MAX_DEGREE_DEFAULT = 32;
path: include/svs/lib/preprocessor.h
user: login: mihaic
body: Can you please look at the docs corresponding to the PR and confirm these `*_DEFAULT` values are visible? Users should be able to see the default value without reading the code. Ideally, there should be numbers visible in the `VamanaBuildParameters` doc [as currently](https://intel.github.io/ScalableVectorSearch/python/vamana.html#svs.VamanaBuildParameters.__init__); alternatively, there should be separate doc entries for the `*_DEFAULT` consts.
created_at: 2025-03-24T17:03:10Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
+            py::arg("graph_max_degree") = svs::GRAPH_MAX_DEGREE_DEFAULT,
+            py::arg("window_size") = svs::WINDOW_SIZE_DEFAULT,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: Could you please add a description in the docs (right below, PR line 442) for the `*_PLACEHOLDER` values? It could be something like this:
> Default is `graph_max_degree * 2`.
created_at: 2025-03-24T17:12:04Z
author_association: MEMBER
diff_hunk: @@ -959,4 +962,66 @@ auto auto_assemble(
     index.apply(config);
     return index;
 }
+
+/// @brief Verify parameters and set defaults if needed
+template <typename Dist>
+void verify_and_set_default_index_parameters(
+    VamanaBuildParameters& parameters, Dist distance_function
+) {
+    // Set default values
+    if (parameters.max_candidate_pool_size == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        parameters.max_candidate_pool_size = 2 * parameters.graph_max_degree;
+    }
+
+    if (parameters.prune_to == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        if (parameters.graph_max_degree >= 16) {
+            parameters.prune_to = parameters.graph_max_degree - 4;
+        } else {
+            parameters.prune_to = parameters.graph_max_degree;
+        }
+    }
+
+    // Check supported distance type using std::is_same type trait
+    using dist_type = std::decay_t<decltype(distance_function)>;
+    // Create type flags for each distance type
+    constexpr bool is_L2 = std::is_same_v<dist_type, svs::distance::DistanceL2>;
+    constexpr bool is_IP = std::is_same_v<dist_type, svs::distance::DistanceIP>;
+    constexpr bool is_Cosine =
+        std::is_same_v<dist_type, svs::distance::DistanceCosineSimilarity>;
+
+    if (parameters.alpha == svs::FLOAT_PLACEHOLDER) {
+        // Check if it's a supported distance type
+        if (is_L2) {
+            parameters.alpha = 1.2f;
path: include/svs/index/vamana/index.h
user: login: mihaic
body: Good idea with the `*_DEFAULT` values! (I was only suggesting numerical values). What do you think about adding two more for the two alpha values for maintainability, e.g., `ALPHA_MAXIMIZE_DEFAULT` and `ALPHA_MINIMIZE_DEFAULT`? Feel free to say no.
created_at: 2025-03-24T17:16:37Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: This deprecation expiry should be noted in the release notes. I guess we don't have a formal way to record in-progress release notes (issue #98), so at lease it should be prominently noted in the PR description so it shows up in the PR squash commit message.
created_at: 2025-03-24T17:28:32Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
+            py::arg("graph_max_degree") = svs::GRAPH_MAX_DEGREE_DEFAULT,
+            py::arg("window_size") = svs::WINDOW_SIZE_DEFAULT,
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, added!
created_at: 2025-03-24T21:56:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -959,4 +962,66 @@ auto auto_assemble(
     index.apply(config);
     return index;
 }
+
+/// @brief Verify parameters and set defaults if needed
+template <typename Dist>
+void verify_and_set_default_index_parameters(
+    VamanaBuildParameters& parameters, Dist distance_function
+) {
+    // Set default values
+    if (parameters.max_candidate_pool_size == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        parameters.max_candidate_pool_size = 2 * parameters.graph_max_degree;
+    }
+
+    if (parameters.prune_to == svs::UNSIGNED_INTEGER_PLACEHOLDER) {
+        if (parameters.graph_max_degree >= 16) {
+            parameters.prune_to = parameters.graph_max_degree - 4;
+        } else {
+            parameters.prune_to = parameters.graph_max_degree;
+        }
+    }
+
+    // Check supported distance type using std::is_same type trait
+    using dist_type = std::decay_t<decltype(distance_function)>;
+    // Create type flags for each distance type
+    constexpr bool is_L2 = std::is_same_v<dist_type, svs::distance::DistanceL2>;
+    constexpr bool is_IP = std::is_same_v<dist_type, svs::distance::DistanceIP>;
+    constexpr bool is_Cosine =
+        std::is_same_v<dist_type, svs::distance::DistanceCosineSimilarity>;
+
+    if (parameters.alpha == svs::FLOAT_PLACEHOLDER) {
+        // Check if it's a supported distance type
+        if (is_L2) {
+            parameters.alpha = 1.2f;
path: include/svs/index/vamana/index.h
user: login: yuejiaointel
body: Good idea, added!
created_at: 2025-03-24T21:56:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -420,40 +421,21 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Sure, I modified the PR description
created_at: 2025-03-24T21:57:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,18 +448,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is graph_max_degree * 2.
path: bindings/python/src/vamana.cpp
user: login: ibhati
body: ```suggestion
                    The default value is `graph_max_degree` * 2.
```
created_at: 2025-03-26T16:10:13Z
author_association: MEMBER
diff_hunk: @@ -462,18 +448,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is graph_max_degree * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is graph_max_degree - 4 if
path: bindings/python/src/vamana.cpp
user: login: ibhati
body: ```suggestion
                    `graph_max_degree`. The default value is `graph_max_degree` - 4 if
```
created_at: 2025-03-26T16:10:55Z
author_association: MEMBER
diff_hunk: @@ -462,18 +448,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is graph_max_degree * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is graph_max_degree - 4 if
+                    graph_max_degree is at least 16, otherwise it equals graph_max_degree.
path: bindings/python/src/vamana.cpp
user: login: ibhati
body: ```suggestion
                    `graph_max_degree` is at least 16, otherwise it equals `graph_max_degree`.
```
created_at: 2025-03-26T16:12:07Z
author_association: MEMBER
diff_hunk: @@ -896,10 +897,12 @@ auto auto_build(
     auto entry_point = extensions::compute_entry_point(data, threadpool);
 
     // Default graph.
-    auto graph = default_graph(data.size(), parameters.graph_max_degree, graph_allocator);
+    auto verified_parameters = parameters;
+    verify_and_set_default_index_parameters(verified_parameters, distance);
path: include/svs/index/vamana/index.h
user: login: yuejiaointel
body: I verified parameters here because we are building the graph using parameters.graph_max_degree, but if it is okay to not verify for the graph, I can remove it
created_at: 2025-03-26T16:29:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,18 +448,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is graph_max_degree * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is graph_max_degree - 4 if
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, fixed!
created_at: 2025-03-26T18:44:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,18 +448,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is graph_max_degree * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is graph_max_degree - 4 if
+                    graph_max_degree is at least 16, otherwise it equals graph_max_degree.
path: bindings/python/src/vamana.cpp
user: login: yuejiaointel
body: Thx, fixed!
created_at: 2025-03-26T18:45:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -159,3 +162,14 @@ inline constexpr bool have_avx512_avx2 = true;
 #endif
 
 } // namespace svs::arch
+
+namespace svs {
path: include/svs/lib/preprocessor.h
user: login: dian-lun-lin
body: Thank you for the good work.

Since some of these parameters are vamana-specific, could we move these parameters to svs::index::vamana namespace? Or change the name to Vamana specific.

For example, GRAPH_MAX_DEGREE_DEFAULT -> VAMANA_GRAPH_MAX_DEGREE_DEFAULT. 
ALPHA_*, USE_FULL_SEARCH_HISTORY_DEFAULT,  WINDOW_SIZE_DEFAULT should also be changed to Vamana specific
created_at: 2025-03-27T21:10:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -159,3 +162,14 @@ inline constexpr bool have_avx512_avx2 = true;
 #endif
 
 } // namespace svs::arch
+
+namespace svs {
path: include/svs/lib/preprocessor.h
user: login: yuejiaointel
body: Thx for suggestion, fixed!
created_at: 2025-03-27T21:25:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
                    The default value is 1.2 for L2 distance type and 0.95 for MIP/Cosine.
```
created_at: 2025-03-28T00:19:05Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
                    of a larger memory footprint.
```
created_at: 2025-03-28T00:20:32Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
```
created_at: 2025-03-28T00:20:50Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,26 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            // L2 distance type default 1.2, IP/Cosine 0.95
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
```
created_at: 2025-03-28T00:23:41Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,26 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            // L2 distance type default 1.2, IP/Cosine 0.95
+            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
+            py::arg("graph_max_degree") = svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT,
+            py::arg("window_size") = svs::VAMANA_WINDOW_SIZE_DEFAULT,
+            // Default is graph_max_degree * 2
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
```
created_at: 2025-03-28T00:23:50Z
author_association: MEMBER
diff_hunk: @@ -420,40 +421,26 @@ void wrap(py::module& m) {
                         size_t window_size,
                         size_t max_candidate_pool_size,
                         size_t prune_to,
-                        size_t num_threads) {
-                if (num_threads != std::numeric_limits<size_t>::max()) {
-                    PyErr_WarnEx(
-                        PyExc_DeprecationWarning,
-                        "Constructing VamanaBuildParameters with the \"num_threads\" "
-                        "keyword "
-                        "argument is deprecated, no longer has any effect, and will be "
-                        "removed "
-                        "from future versions of the library. Use the \"num_threads\" "
-                        "keyword "
-                        "argument of \"svs.Vamana.build\" instead!",
-                        1
-                    );
-                }
-
-                // Default the `prune_to` argument appropriately.
-                if (prune_to == std::numeric_limits<size_t>::max()) {
-                    prune_to = graph_max_degree;
-                }
-
+                        bool use_full_search_history) {
                 return svs::index::vamana::VamanaBuildParameters{
                     alpha,
                     graph_max_degree,
                     window_size,
                     max_candidate_pool_size,
                     prune_to,
-                    true};
+                    use_full_search_history};
             }),
-            py::arg("alpha") = 1.2,
-            py::arg("graph_max_degree") = 32,
-            py::arg("window_size") = 64,
-            py::arg("max_candidate_pool_size") = 80,
-            py::arg("prune_to") = std::numeric_limits<size_t>::max(),
-            py::arg("num_threads") = std::numeric_limits<size_t>::max(),
+            // L2 distance type default 1.2, IP/Cosine 0.95
+            py::arg("alpha") = svs::FLOAT_PLACEHOLDER,
+            py::arg("graph_max_degree") = svs::VAMANA_GRAPH_MAX_DEGREE_DEFAULT,
+            py::arg("window_size") = svs::VAMANA_WINDOW_SIZE_DEFAULT,
+            // Default is graph_max_degree * 2
+            py::arg("max_candidate_pool_size") = svs::UNSIGNED_INTEGER_PLACEHOLDER,
+            // If graph_max_degree >= 16, default graph_max_degree - 4, otherwise
+            // graph_max_degree
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
```
created_at: 2025-03-28T00:24:19Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is `graph_max_degree` * 2.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
                    The default value is ``graph_max_degree`` * 2.
```
created_at: 2025-03-28T00:25:03Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is `graph_max_degree` * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is `graph_max_degree` - 4 if
+                    `graph_max_degree` is at least 16, otherwise it equals `graph_max_degree`.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
                    ` `graph_max_degree`` - 4 if
                    ``graph_max_degree`` is at least 16, otherwise ``graph_max_degree``.
```
created_at: 2025-03-28T00:28:01Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is `graph_max_degree` * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
-                    `graph_max_degree`.
+                    `graph_max_degree`. The default value is `graph_max_degree` - 4 if
+                    `graph_max_degree` is at least 16, otherwise it equals `graph_max_degree`.
+                use_full_search_history: When true, uses the full search history during
+                    graph construction, which can improve graph quality at the expense of
+                    additional memory and potentially longer build times.
+                    The default value is true.
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
```
created_at: 2025-03-28T00:28:23Z
author_association: MEMBER
diff_hunk: @@ -210,12 +214,20 @@ class MutableVamanaIndex {
         , distance_(std::move(distance_function))
         , threadpool_(threads::as_threadpool(std::move(threadpool_proto)))
         , search_parameters_(vamana::construct_default_search_parameters(data_))
-        , construction_window_size_(parameters.window_size)
-        , max_candidates_(parameters.max_candidate_pool_size)
-        , prune_to_(parameters.prune_to)
-        , alpha_(parameters.alpha)
-        , use_full_search_history_{parameters.use_full_search_history}
+        , build_parameters_(parameters)
         , logger_{std::move(logger)} {
+        // Verify and set defaults directly on the input parameters
+        verify_and_set_default_index_parameters(build_parameters_, distance_function);
+
+        // Initialize with unverified parameters first as there are no default constructors,
+        // Set it again it verify function may change values
path: include/svs/index/vamana/dynamic_index.h
user: login: mihaic
body: Can you please rephrase this comment? I'm not sure what it means.
created_at: 2025-03-28T00:30:57Z
author_association: MEMBER
diff_hunk: @@ -462,18 +449,26 @@ void wrap(py::module& m) {
                     For distance types favoring minimization, set this to a number
                     greater than 1.0 (typically, 1.2 is sufficient). For distance types
                     preferring maximization, set to a value less than 1.0 (such as 0.95).
+                    The default value is 1.2 for L2 distance type and 0.95 for IP/Cosine.
                 graph_max_degree: The maximum out-degree in the final graph. Graphs with
                     a higher degree tend to yield better accuracy and performance at the cost
-                    of a larger memory footprint.
+                    of a larger memory footprint. The default value is 32.
                 window_size: Parameter controlling the quality of graph construction. A
                     larger window size will yield a higher-quality index at the cost of
                     longer construction time. Should be larger than `graph_max_degree`.
+                    The default value is 64.
                 max_candidate_pool_size: Limit on the number of candidates to consider
                     for neighbor updates. Should be larger than `window_size`.
+                    The default value is `graph_max_degree` * 2.
                 prune_to: Amount candidate lists will be pruned to when exceeding the
                     target max degree. In general, setting this to slightly less than
                     `graph_max_degree` will yield faster index building times. Default:
path: bindings/python/src/vamana.cpp
user: login: mihaic
body: ```suggestion
                    ``graph_max_degree`` will yield faster index building times. Default:
```
created_at: 2025-03-28T00:38:20Z
author_association: MEMBER
diff_hunk: @@ -210,12 +214,20 @@ class MutableVamanaIndex {
         , distance_(std::move(distance_function))
         , threadpool_(threads::as_threadpool(std::move(threadpool_proto)))
         , search_parameters_(vamana::construct_default_search_parameters(data_))
-        , construction_window_size_(parameters.window_size)
-        , max_candidates_(parameters.max_candidate_pool_size)
-        , prune_to_(parameters.prune_to)
-        , alpha_(parameters.alpha)
-        , use_full_search_history_{parameters.use_full_search_history}
+        , build_parameters_(parameters)
         , logger_{std::move(logger)} {
+        // Verify and set defaults directly on the input parameters
+        verify_and_set_default_index_parameters(build_parameters_, distance_function);
+
+        // Initialize with unverified parameters first as there are no default constructors,
+        // Set it again it verify function may change values
path: include/svs/index/vamana/dynamic_index.h
user: login: yuejiaointel
body: Fixed! basically need to set graph twice because verify function might change value to graph_max_degree. 
created_at: 2025-03-28T00:52:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: mihaic
created_at: 2025-03-25T01:51:06Z
body: /intelci
author_association: MEMBER
user: login: yuejiaointel
created_at: 2025-03-25T05:36:14Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T05:37:04Z
body: /intelci
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T05:38:42Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T05:46:54Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T06:00:47Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T06:01:54Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T06:13:00Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T06:36:06Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T06:57:38Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T16:25:07Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T17:04:01Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T17:15:14Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-25T17:55:45Z
body: /intelci
set ref=fix_set_default_build_params
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T00:37:37Z
body: /intelci
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T00:40:43Z
body: /intelci
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T06:43:11Z
body: /intelci
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T19:31:17Z
body: intelci
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T19:32:05Z
body: /intelci
set ref=fix_set_default_build_params_test
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-26T20:55:55Z
body: /intelci
set ref=fix_set_default_build_params_test
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T01:30:02Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T01:37:58Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T04:32:27Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T05:54:40Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T18:49:32Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: ibhati
created_at: 2025-03-27T20:36:13Z
body: @mihaic can you please check if your requested changes have been made? Thanks!
author_association: MEMBER
user: login: yuejiaointel
created_at: 2025-03-27T21:38:37Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T22:01:43Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: yuejiaointel
created_at: 2025-03-27T22:30:28Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR
user: login: mihaic
created_at: 2025-03-28T16:44:57Z
body: @yuejiaointel, please try changing the CIBuildWheel workflow to use Ubuntu 22.04:
https://github.com/intel/ScalableVectorSearch/actions/runs/14119826155/workflow?pr=96#L33
author_association: MEMBER
user: login: mihaic
created_at: 2025-03-28T17:20:04Z
body: Ubuntu 24.04 didn't help...
author_association: MEMBER
user: login: yuejiaointel
created_at: 2025-03-28T18:33:11Z
body: /intelci
set ref=fix_set_default_build_params_test_back
author_association: CONTRIBUTOR