diff --git a/include/xtensor/misc/xsort.hpp b/include/xtensor/misc/xsort.hpp index 196ec45cd..82b1f1317 100644 --- a/include/xtensor/misc/xsort.hpp +++ b/include/xtensor/misc/xsort.hpp @@ -318,6 +318,7 @@ namespace xt return comp(*(data_begin + i), *(data_begin + j)); } ); + break; } case (sorting_method::stable): { @@ -329,6 +330,7 @@ namespace xt return comp(*(data_begin + i), *(data_begin + j)); } ); + break; } } } diff --git a/test/test_xsort.cpp b/test/test_xsort.cpp index bbe928d4d..612062bba 100644 --- a/test/test_xsort.cpp +++ b/test/test_xsort.cpp @@ -7,6 +7,10 @@ * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ +#include +#include +#include + #include "xtensor/containers/xadapt.hpp" #include "xtensor/containers/xarray.hpp" #include "xtensor/containers/xfixed.hpp" @@ -176,6 +180,44 @@ namespace xt EXPECT_EQ(ex, xt::argsort(a, {0}, xt::sorting_method::stable)); } + TEST(xsort, argsort_quick_sorts_once) + { + // The quick method must not fall through to the stable sort: both + // orderings are valid, so only the number of comparisons tells them apart. + const std::vector data = {5., 3., 8., 1., 9., 2., 7., 4., 6., 0., 3., 8., 1., 5., 2.}; + + std::size_t argsort_comparisons = 0; + std::vector indices(data.size()); + detail::argsort_iter( + data.cbegin(), + data.cend(), + indices.begin(), + indices.end(), + [&argsort_comparisons](double lhs, double rhs) + { + ++argsort_comparisons; + return lhs < rhs; + }, + sorting_method::quick + ); + + std::size_t sort_comparisons = 0; + std::vector expected(data.size()); + std::iota(expected.begin(), expected.end(), std::size_t(0)); + std::sort( + expected.begin(), + expected.end(), + [&](std::size_t i, std::size_t j) + { + ++sort_comparisons; + return data[i] < data[j]; + } + ); + + EXPECT_EQ(indices, expected); + EXPECT_EQ(argsort_comparisons, sort_comparisons); + } + TEST(xsort, sort_easy) { xarray a = {{5, 3, 1}, {4, 4, 4}};