File indexing completed on 2026-11-09 09:28:52
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Seeding/DoubletSeedFinder.hpp"
0012
0013 #include <algorithm>
0014 #include <cfenv>
0015 #include <cmath>
0016 #include <cstddef>
0017 #include <limits>
0018 #include <random>
0019 #include <vector>
0020
0021 using namespace Acts;
0022
0023 namespace ActsTests {
0024
0025 namespace {
0026
0027 using IndexAndCotTheta = DoubletsForMiddleSp::IndexAndCotTheta;
0028
0029 DoubletsForMiddleSp doubletsOf(const std::vector<float>& cotThetas) {
0030 DoubletsForMiddleSp doublets;
0031 for (std::size_t k = 0; k < cotThetas.size(); ++k) {
0032 doublets.emplace_back(static_cast<SpacePointIndex>(k), cotThetas[k], 1.f,
0033 1.f, 0.f, 0.f, 0.f, 0.f);
0034 }
0035 return doublets;
0036 }
0037
0038
0039
0040
0041 void checkSorted(const std::vector<float>& cotThetas,
0042 const DoubletsForMiddleSp::IndexRange& range,
0043 const std::vector<IndexAndCotTheta>& sorted) {
0044 std::vector<IndexAndCotTheta> expected;
0045 for (auto i = range.first; i < range.second; ++i) {
0046 expected.push_back({i, cotThetas[i]});
0047 }
0048 std::ranges::stable_sort(expected, {}, &IndexAndCotTheta::cotTheta);
0049
0050 std::vector<DoubletsForMiddleSp::Index> expectedIndices;
0051 std::vector<DoubletsForMiddleSp::Index> sortedIndices;
0052 std::vector<bool> expectedSigns;
0053 std::vector<bool> sortedSigns;
0054 for (const IndexAndCotTheta& item : expected) {
0055 expectedIndices.push_back(item.index);
0056 expectedSigns.push_back(std::signbit(item.cotTheta));
0057 }
0058 for (const IndexAndCotTheta& item : sorted) {
0059 sortedIndices.push_back(item.index);
0060 sortedSigns.push_back(std::signbit(item.cotTheta));
0061 }
0062
0063 BOOST_CHECK_EQUAL_COLLECTIONS(sortedIndices.begin(), sortedIndices.end(),
0064 expectedIndices.begin(), expectedIndices.end());
0065 BOOST_CHECK_EQUAL_COLLECTIONS(sortedSigns.begin(), sortedSigns.end(),
0066 expectedSigns.begin(), expectedSigns.end());
0067 }
0068
0069
0070
0071 void sortWithoutFpe(const DoubletsForMiddleSp& doublets,
0072 const DoubletsForMiddleSp::IndexRange& range,
0073 std::vector<IndexAndCotTheta>& sorted,
0074 DoubletsForMiddleSp::SortStorage* storage) {
0075 std::feclearexcept(FE_ALL_EXCEPT);
0076 if (storage != nullptr) {
0077 doublets.sortByCotTheta(range, sorted, *storage);
0078 } else {
0079 doublets.sortByCotTheta(range, sorted);
0080 }
0081 BOOST_CHECK(!std::fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW));
0082 }
0083
0084
0085 void checkSort(const std::vector<float>& cotThetas,
0086 DoubletsForMiddleSp::SortStorage& storage) {
0087 const DoubletsForMiddleSp doublets = doubletsOf(cotThetas);
0088 const DoubletsForMiddleSp::IndexRange range{0, doublets.size()};
0089 std::vector<IndexAndCotTheta> sorted;
0090 sortWithoutFpe(doublets, range, sorted, &storage);
0091 checkSorted(cotThetas, range, sorted);
0092 }
0093
0094 std::vector<float> uniformCotThetas(std::size_t n, std::mt19937& rng) {
0095 std::uniform_real_distribution<float> uniform(-5.f, 5.f);
0096 std::vector<float> cotThetas(n);
0097 for (float& cotTheta : cotThetas) {
0098 cotTheta = uniform(rng);
0099 }
0100 return cotThetas;
0101 }
0102
0103 }
0104
0105 BOOST_AUTO_TEST_SUITE(SeedingSuite)
0106
0107 BOOST_AUTO_TEST_CASE(SortByCotThetaMatchesStableSort) {
0108 std::mt19937 rng(42);
0109
0110 DoubletsForMiddleSp::SortStorage storage;
0111
0112 for (std::size_t n : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15,
0113 16, 17, 31, 32, 33, 40, 64, 65, 100, 1024, 3000, 33}) {
0114 checkSort(uniformCotThetas(n, rng), storage);
0115 }
0116 }
0117
0118 BOOST_AUTO_TEST_CASE(SortByCotThetaKeepsOrderOfEqualCotTheta) {
0119 std::mt19937 rng(7);
0120 std::uniform_int_distribution<int> fewValues(-3, 3);
0121 DoubletsForMiddleSp::SortStorage storage;
0122 for (std::size_t n : {5, 10, 40, 41, 500, 2000}) {
0123 std::vector<float> cotThetas(n);
0124 for (float& cotTheta : cotThetas) {
0125 cotTheta = static_cast<float>(fewValues(rng));
0126 }
0127 checkSort(cotThetas, storage);
0128 }
0129
0130
0131 for (std::size_t n : {6, 30, 300}) {
0132 checkSort(std::vector<float>(n, 1.f), storage);
0133 }
0134 }
0135
0136 BOOST_AUTO_TEST_CASE(SortByCotThetaKeepsSignedZeros) {
0137 DoubletsForMiddleSp::SortStorage storage;
0138 for (std::size_t n : {6, 20, 200}) {
0139 std::vector<float> cotThetas(n);
0140 for (std::size_t k = 0; k < n; ++k) {
0141 if (k % 3 == 0) {
0142 cotThetas[k] = -0.f;
0143 } else if (k % 3 == 1) {
0144 cotThetas[k] = 0.f;
0145 } else {
0146 cotThetas[k] = 1.f - 0.01f * static_cast<float>(k);
0147 }
0148 }
0149 checkSort(cotThetas, storage);
0150 }
0151 }
0152
0153 BOOST_AUTO_TEST_CASE(SortByCotThetaFallsBackForInfiniteCotTheta) {
0154 const float inf = std::numeric_limits<float>::infinity();
0155 DoubletsForMiddleSp::SortStorage storage;
0156 for (std::size_t n : {6, 20, 200, 1000}) {
0157 std::vector<float> cotThetas(n);
0158 for (std::size_t k = 0; k < n; ++k) {
0159 cotThetas[k] = static_cast<float>(n - k);
0160 }
0161 cotThetas[n / 2] = inf;
0162 cotThetas[n / 3] = -inf;
0163 checkSort(cotThetas, storage);
0164 }
0165 }
0166
0167 BOOST_AUTO_TEST_CASE(SortByCotThetaFallsBackForTinyRange) {
0168
0169 const float smallest = std::numeric_limits<float>::denorm_min();
0170 DoubletsForMiddleSp::SortStorage storage;
0171 for (std::size_t n : {6, 20, 200, 1000}) {
0172 std::vector<float> cotThetas(n);
0173 for (std::size_t k = 0; k < n; ++k) {
0174 cotThetas[k] = (k % 2 == 0) ? 0.f : smallest;
0175 }
0176 checkSort(cotThetas, storage);
0177 }
0178 }
0179
0180 BOOST_AUTO_TEST_CASE(SortByCotThetaHandlesOneOutlier) {
0181
0182 std::mt19937 rng(11);
0183 std::uniform_real_distribution<float> narrow(-0.005f, 0.005f);
0184 DoubletsForMiddleSp::SortStorage storage;
0185 for (std::size_t n : {6, 20, 200, 1000}) {
0186 std::vector<float> cotThetas(n);
0187 for (float& cotTheta : cotThetas) {
0188 cotTheta = narrow(rng);
0189 }
0190 cotThetas[n / 2] = 27.f;
0191 checkSort(cotThetas, storage);
0192 }
0193 }
0194
0195 BOOST_AUTO_TEST_CASE(SortByCotThetaSortsRangesWithBothOverloads) {
0196 std::mt19937 rng(5);
0197 for (std::size_t n : {0, 5, 30, 300}) {
0198 const std::vector<float> cotThetas = uniformCotThetas(n + 20, rng);
0199 const DoubletsForMiddleSp doublets = doubletsOf(cotThetas);
0200
0201
0202 const DoubletsForMiddleSp::IndexRange range{
0203 10, static_cast<DoubletsForMiddleSp::Index>(10 + n)};
0204
0205 std::vector<IndexAndCotTheta> allocating;
0206 sortWithoutFpe(doublets, range, allocating, nullptr);
0207 checkSorted(cotThetas, range, allocating);
0208
0209 std::vector<IndexAndCotTheta> withStorage;
0210 DoubletsForMiddleSp::SortStorage storage;
0211 sortWithoutFpe(doublets, range, withStorage, &storage);
0212 checkSorted(cotThetas, range, withStorage);
0213 }
0214 }
0215
0216 BOOST_AUTO_TEST_SUITE_END()
0217
0218 }