diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/index_mapping.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/index_mapping.hpp index 15a895164..16f336173 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/index_mapping.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/index_mapping.hpp @@ -89,7 +89,7 @@ struct DenseIndexMapping { IdxVector reorder; }; -namespace detail { +namespace index_mapping::detail { inline auto build_dense_mapping_comparison_sort(IdxVector const& idx_B_in_A, Idx const /* n_B */) { using DenseEntry = std::pair; @@ -118,22 +118,34 @@ inline auto build_dense_mapping_comparison_sort(IdxVector const& idx_B_in_A, Idx inline auto build_dense_mapping_counting_sort(IdxVector const& idx_B_in_A, Idx const n_B) { auto sparse_result = build_sparse_mapping(idx_B_in_A, n_B); - return DenseIndexMapping{.indvector = sparse_decode(sparse_result.indptr), + return DenseIndexMapping{.indvector = power_grid_model::detail::sparse_decode(sparse_result.indptr), .reorder = std::move(sparse_result.reorder)}; } -} // namespace detail +struct IndexMappingApproachCriterion { + double n_a_prefactor{}; + double n_a_log_n_a_prefactor{}; + double constant{}; -inline DenseIndexMapping build_dense_mapping(IdxVector const& idx_B_in_A, Idx const n_B) { - constexpr auto relative_complexity_prefactor = 1.0; + constexpr bool operator()(std::integral auto n_A, std::integral auto n_B) const { + auto const n_A_ = static_cast(n_A); + auto const n_B_ = static_cast(n_B); + + return n_B_ < n_a_prefactor * n_A_ + n_a_log_n_a_prefactor * n_A_ * log(n_A_) + constant; + } +}; + +constexpr IndexMappingApproachCriterion index_mapping_criterion_gcc{.n_a_prefactor = -0.00733595283054587, + .n_a_log_n_a_prefactor = 0.01888288636738604, + .constant = 20.338844396105696}; - auto const n_A_ = static_cast(idx_B_in_A.size()); - auto const n_B_ = static_cast(n_B); +} // namespace index_mapping::detail - if (n_A_ + n_B_ < relative_complexity_prefactor * n_A_ * log(n_A_)) { - return detail::build_dense_mapping_counting_sort(idx_B_in_A, n_B); +inline DenseIndexMapping build_dense_mapping(IdxVector const& idx_B_in_A, Idx const n_B) { + if (index_mapping::detail::index_mapping_criterion_gcc(idx_B_in_A.size(), n_B)) { + return index_mapping::detail::build_dense_mapping_counting_sort(idx_B_in_A, n_B); } - return detail::build_dense_mapping_comparison_sort(idx_B_in_A, n_B); + return index_mapping::detail::build_dense_mapping_comparison_sort(idx_B_in_A, n_B); } } // namespace power_grid_model diff --git a/tests/cpp_unit_tests/test_index_mapping.cpp b/tests/cpp_unit_tests/test_index_mapping.cpp index 3da12dfa5..3cd5944e0 100644 --- a/tests/cpp_unit_tests/test_index_mapping.cpp +++ b/tests/cpp_unit_tests/test_index_mapping.cpp @@ -17,33 +17,64 @@ TEST_CASE("Test sparse mapping") { CHECK(mapping.reorder == mapping_2.reorder); } -TEST_CASE("Test dense mapping - counting sort") { - IdxVector const idx_B_in_A{3, 5, 2, 1, 1, 2}; - DenseIndexMapping const mapping{{1, 1, 2, 2, 3, 5}, {3, 4, 2, 5, 0, 1}}; - DenseIndexMapping const mapping_2 = build_dense_mapping(idx_B_in_A, 7); +TEST_CASE("Test dense mapping - comparison sort") { + constexpr Idx count{10}; + constexpr Idx n_B = 100000; - CHECK(mapping.indvector == mapping_2.indvector); - CHECK(mapping.reorder == mapping_2.reorder); - CHECK(mapping_2.indvector.begin() == std::ranges::min_element(mapping_2.indvector)); - CHECK(mapping_2.indvector.end() - 1 == std::ranges::max_element(mapping_2.indvector)); + double decrement = static_cast(n_B) / count; + + IdxVector idx_B_in_A(count); + for (Idx i = 0; i < count; ++i) { + idx_B_in_A[i] = static_cast(static_cast(n_B) - static_cast(i) * decrement); + } + + IdxVector sorted_idx_B_in_A = idx_B_in_A; + std::ranges::sort(sorted_idx_B_in_A); + + DenseIndexMapping const mapping = build_dense_mapping(idx_B_in_A, n_B); + + CHECK(mapping.indvector == sorted_idx_B_in_A); + CHECK(mapping.indvector.begin() == std::ranges::min_element(mapping.indvector)); + CHECK(mapping.indvector.end() - 1 == std::ranges::max_element(mapping.indvector)); } -TEST_CASE("Test dense mapping - comparison sort") { - constexpr Idx count{1'000'000}; +TEST_CASE("Test dense mapping index criterion - comparison sort") { + constexpr Idx count{10}; + constexpr Idx n_B = 100000; + + auto result = index_mapping::detail::index_mapping_criterion_gcc(count, n_B); + + CHECK(result == false); +} + +TEST_CASE("Test dense mapping - counting sort") { + constexpr Idx count{1000000}; + constexpr Idx n_B = 10; + + double decrement = static_cast(n_B) / count; IdxVector idx_B_in_A(count); for (Idx i = 0; i < count; ++i) { - idx_B_in_A[i] = count - 1 - i; + idx_B_in_A[i] = static_cast(static_cast(n_B - 1) - static_cast(i) * decrement); } IdxVector sorted_idx_B_in_A = idx_B_in_A; std::ranges::sort(sorted_idx_B_in_A); - DenseIndexMapping const mapping = build_dense_mapping(idx_B_in_A, count); + DenseIndexMapping const mapping = build_dense_mapping(idx_B_in_A, n_B); CHECK(mapping.indvector == sorted_idx_B_in_A); CHECK(mapping.indvector.begin() == std::ranges::min_element(mapping.indvector)); CHECK(mapping.indvector.end() - 1 == std::ranges::max_element(mapping.indvector)); } +TEST_CASE("Test dense mapping index criterion - counting sort") { + constexpr Idx count{1000000}; + constexpr Idx n_B = 10; + + auto result = index_mapping::detail::index_mapping_criterion_gcc(count, n_B); + + CHECK(result == true); +} + } // namespace power_grid_model