File indexing completed on 2026-05-10 08:02:34
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Seeding2/HoughAccumulatorSection.hpp"
0012 #include "Acts/Utilities/Logger.hpp"
0013
0014 #include <functional>
0015 #include <map>
0016 #include <vector>
0017
0018 using namespace Acts;
0019 using namespace Acts::Experimental;
0020
0021 namespace ActsTests {
0022
0023 auto logger = getDefaultLogger("UnitTests", Logging::VERBOSE);
0024
0025
0026
0027 struct LineParameters {
0028 float slope;
0029 float intercept;
0030 };
0031
0032
0033 struct Stats {
0034 double area{};
0035 std::int32_t nSections{};
0036 std::int32_t nLines{};
0037 std::int32_t discardedByThresholdCut{};
0038 std::int32_t discardedByCrossingCut{};
0039 };
0040
0041 template <typename measurement_t = LineParameters>
0042 struct TestExplorationOptions : public HoughExplorationOptions<LineParameters> {
0043 std::uint32_t threshold =
0044 4;
0045 std::uint32_t noiseThreshold = 12;
0046
0047 std::uint32_t min_division_level = 2;
0048 };
0049
0050
0051 BOOST_AUTO_TEST_SUITE(HoughAccumulatorSectionSuite)
0052
0053 using namespace ActsTests;
0054
0055 BOOST_AUTO_TEST_CASE(construct) {
0056 HoughAccumulatorSection s(10., 100., -5., -50.0);
0057 BOOST_CHECK_EQUAL(s.xSize(), 10.);
0058 BOOST_CHECK_EQUAL(s.ySize(), 100.);
0059 BOOST_CHECK_EQUAL(s.xBegin(), -5.);
0060 BOOST_CHECK_EQUAL(s.yBegin(), -50.);
0061 }
0062
0063 BOOST_AUTO_TEST_CASE(split_vertical) {
0064 HoughAccumulatorSection s(10., 100., -5., -50.0);
0065 HoughAccumulatorSection t = s.top();
0066 HoughAccumulatorSection b = s.bottom();
0067 BOOST_CHECK_EQUAL(s.xSize(), t.xSize());
0068 BOOST_CHECK_EQUAL(s.xSize(), b.xSize());
0069 BOOST_CHECK_EQUAL(0.5f * s.ySize(), t.ySize());
0070 BOOST_CHECK_EQUAL(0.5f * s.ySize(), b.ySize());
0071 BOOST_CHECK_EQUAL(s.xBegin(), t.xBegin());
0072 BOOST_CHECK_EQUAL(s.xBegin(), b.xBegin());
0073 BOOST_CHECK_EQUAL(t.yBegin(), 0.0);
0074 BOOST_CHECK_EQUAL(b.yBegin(), -50.0);
0075 }
0076
0077 BOOST_AUTO_TEST_CASE(split_horizontal) {
0078 HoughAccumulatorSection s(10., 100., -5., -50.0);
0079 HoughAccumulatorSection l = s.left();
0080 HoughAccumulatorSection r = s.right();
0081 BOOST_CHECK_EQUAL(s.ySize(), l.ySize());
0082 BOOST_CHECK_EQUAL(s.ySize(), r.ySize());
0083 BOOST_CHECK_EQUAL(0.5f * s.xSize(), l.xSize());
0084 BOOST_CHECK_EQUAL(0.5f * s.xSize(), r.xSize());
0085 BOOST_CHECK_EQUAL(l.xBegin(), -5.0);
0086 BOOST_CHECK_EQUAL(r.xBegin(), 0.0);
0087 }
0088
0089 BOOST_AUTO_TEST_CASE(split_4) {
0090 HoughAccumulatorSection s(10., 100., 5., 50.0);
0091 HoughAccumulatorSection tl = s.topLeft();
0092 HoughAccumulatorSection tr = s.topRight();
0093 HoughAccumulatorSection bl = s.bottomLeft();
0094 HoughAccumulatorSection br = s.bottomRight();
0095
0096 BOOST_CHECK_EQUAL(tl.xBegin(), 5.0);
0097 BOOST_CHECK_EQUAL(tl.yBegin(), 100.0);
0098 BOOST_CHECK_EQUAL(tl.xSize(), 5.0);
0099 BOOST_CHECK_EQUAL(tl.ySize(), 50.0);
0100
0101 BOOST_CHECK_EQUAL(tr.xBegin(), 10.0);
0102 BOOST_CHECK_EQUAL(tr.yBegin(), 100.0);
0103 BOOST_CHECK_EQUAL(tr.xSize(), 5.0);
0104 BOOST_CHECK_EQUAL(tr.ySize(), 50.0);
0105
0106 BOOST_CHECK_EQUAL(bl.xBegin(), 5.0);
0107 BOOST_CHECK_EQUAL(bl.yBegin(), 50.0);
0108 BOOST_CHECK_EQUAL(bl.xSize(), 5.0);
0109 BOOST_CHECK_EQUAL(bl.ySize(), 50.0);
0110
0111 BOOST_CHECK_EQUAL(br.xBegin(), 10.0);
0112 BOOST_CHECK_EQUAL(br.yBegin(), 50.0);
0113 BOOST_CHECK_EQUAL(br.xSize(), 5.0);
0114 BOOST_CHECK_EQUAL(br.ySize(), 50.0);
0115 }
0116
0117 BOOST_AUTO_TEST_CASE(is_line_inside) {
0118 HoughAccumulatorSection s(10., 2., -5., -1.0);
0119 BOOST_CHECK(!s.isLineInside([](float x) { return 0.5f * x + 5.f; }));
0120 BOOST_CHECK(s.isLineInside([](float x) { return 0.5f * x + 3.f; }));
0121 BOOST_CHECK(s.isLineInside([](float x) { return 0.1f * x; }));
0122 BOOST_CHECK(s.isLineInside([](float x) { return 1.0f * x - 5.f; }));
0123 BOOST_CHECK(!s.isLineInside([](float x) { return 0.5f * x - 5.f; }));
0124 }
0125
0126 BOOST_AUTO_TEST_CASE(is_crossing_inside) {
0127 HoughAccumulatorSection s(10., 6., -5., -6.);
0128 std::function<float(float)> l1 = [](float x) { return 1.0f * x + 3.f; };
0129 std::function<float(float)> l2 = [](float x) { return 0.5f * x + 1.f; };
0130 std::function<float(float)> l3 = [](float x) { return 0.5f * x - 1.f; };
0131 std::function<float(float)> l4 = [](float x) { return 1.0f * x - 3.f; };
0132
0133 BOOST_CHECK(s.isCrossingInside(l1, l2));
0134 BOOST_CHECK(!s.isCrossingInside(l2, l3));
0135 BOOST_CHECK(!s.isCrossingInside(l1, l3));
0136 BOOST_CHECK(!s.isCrossingInside(l4, l3));
0137 }
0138
0139 BOOST_AUTO_TEST_CASE(history_handing) {
0140 HoughAccumulatorSection s;
0141 s.setHistory(2, 0.6f);
0142 s.setHistory(0, 1.0f);
0143
0144 BOOST_CHECK_EQUAL(s.history(0), 1.0f);
0145 BOOST_CHECK_EQUAL(s.history(2), 0.6f);
0146 }
0147
0148 BOOST_AUTO_TEST_SUITE_END()
0149
0150
0151 BOOST_AUTO_TEST_SUITE(ExploreParametersSpaceSuite)
0152
0153 BOOST_AUTO_TEST_CASE(test_extra_split_x_min_div_0) {
0154
0155
0156
0157
0158
0159
0160 std::vector<LineParameters> measurements = {
0161 {0.05f, 1.0f},
0162 {0.08f, 1.01f},
0163 {-0.10f, 3.0f}
0164 };
0165
0166 TestExplorationOptions<LineParameters> opt;
0167 opt.xMinBinSize = 6.0f;
0168 opt.yMinBinSize = 10.0f;
0169 opt.noiseThreshold = 3;
0170 opt.threshold = 2;
0171 opt.min_division_level = 0;
0172
0173 opt.lineFunctor = [](const LineParameters &p, float arg) {
0174 return p.slope * arg + p.intercept;
0175 };
0176
0177 HoughAccumulatorSection section(20.0f, 20.0f, 0.0f, 0.0f, 0);
0178 section.indices() = {0, 1, 2};
0179
0180 std::map<int, Stats> sStat;
0181
0182 opt.decisionFunctor = [&sStat, &opt](const HoughAccumulatorSection &sec,
0183 const std::vector<LineParameters> &mes) {
0184 using enum HoughAccumulatorSection::Decision;
0185
0186 if (sec.count() < opt.threshold) {
0187 sStat[sec.divisionLevel()].discardedByThresholdCut += 1;
0188 return Discard;
0189 }
0190 if (sec.count() < 3 * opt.threshold &&
0191 !passIntersectionsCheck(sec, mes, opt.lineFunctor,
0192 opt.threshold * (opt.threshold - 1))) {
0193 sStat[sec.divisionLevel()].discardedByCrossingCut += 1;
0194 return Discard;
0195 }
0196
0197 sStat[sec.divisionLevel()].area += sec.xSize() * sec.ySize();
0198 sStat[sec.divisionLevel()].nSections += 1;
0199 sStat[sec.divisionLevel()].nLines += sec.count();
0200
0201 if (sec.divisionLevel() <= opt.min_division_level) {
0202 return Drill;
0203 }
0204 if (sec.count() <= opt.noiseThreshold && sec.xSize() <= opt.xMinBinSize &&
0205 sec.ySize() <= opt.yMinBinSize) {
0206 return Accept;
0207 }
0208
0209 return Drill;
0210 };
0211
0212 std::vector<HoughAccumulatorSection> sectionsStack;
0213 sectionsStack.push_back(std::move(section));
0214 std::vector<HoughAccumulatorSection> results;
0215
0216 exploreHoughParametersSpace(sectionsStack, measurements, opt, results);
0217
0218 BOOST_CHECK(sectionsStack.empty());
0219
0220 BOOST_REQUIRE_EQUAL(results.size(), 1);
0221 BOOST_CHECK_EQUAL(results[0].xSize(), 5.0);
0222 BOOST_CHECK_EQUAL(results[0].ySize(), 10.0);
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 BOOST_CHECK_EQUAL(sStat[1].discardedByThresholdCut, 2);
0239 BOOST_CHECK_EQUAL(sStat[1].discardedByCrossingCut, 1);
0240 BOOST_CHECK_EQUAL(sStat[1].nSections, 1);
0241 BOOST_CHECK_EQUAL(sStat[1].area, 100.0);
0242
0243
0244
0245
0246
0247
0248 BOOST_CHECK_EQUAL(sStat[2].nSections, 1);
0249 BOOST_CHECK_EQUAL(sStat[2].area, 50.0);
0250 BOOST_CHECK_EQUAL(sStat[2].discardedByThresholdCut, 0);
0251 BOOST_CHECK_EQUAL(sStat[2].discardedByCrossingCut, 1);
0252 }
0253
0254 BOOST_AUTO_TEST_CASE(test_with_min_div_lvl_is_1) {
0255
0256
0257
0258
0259
0260
0261
0262
0263 std::vector<LineParameters> measurements = {
0264 {5.0, 3.0},
0265 {4.0, -4.0},
0266 {1.0, 2.0},
0267 {0.5, 7.0},
0268 {0.2, 1.01}
0269 };
0270
0271 TestExplorationOptions<LineParameters> opt;
0272 opt.xMinBinSize = 2.51;
0273 opt.yMinBinSize = 2.51;
0274 opt.noiseThreshold = 3;
0275 opt.threshold = 2;
0276 opt.min_division_level = 1;
0277
0278
0279 opt.lineFunctor = [](const LineParameters &p, float arg) {
0280 return p.slope * arg + p.intercept;
0281 };
0282
0283
0284
0285 HoughAccumulatorSection section(10.0, 20.0, -5.0, -10.0);
0286 section.indices() = {0, 1, 2, 3, 4};
0287
0288
0289 std::map<int, Stats> sStat;
0290
0291
0292 opt.decisionFunctor = [&sStat, &opt](const HoughAccumulatorSection &sec,
0293 const std::vector<LineParameters> &mes) {
0294 using enum HoughAccumulatorSection::Decision;
0295 if (sec.count() < opt.threshold) {
0296 sStat[sec.divisionLevel()].discardedByThresholdCut += 1;
0297 return Discard;
0298 }
0299 if (sec.count() < 3 * opt.threshold &&
0300 !passIntersectionsCheck(sec, mes, opt.lineFunctor,
0301 opt.threshold * (opt.threshold - 1))) {
0302 sStat[sec.divisionLevel()].discardedByCrossingCut += 1;
0303 return Discard;
0304 }
0305
0306 sStat[sec.divisionLevel()].area += sec.xSize() * sec.ySize();
0307 sStat[sec.divisionLevel()].nSections += 1;
0308 sStat[sec.divisionLevel()].nLines += sec.count();
0309
0310 if (sec.divisionLevel() <= opt.min_division_level) {
0311 return Drill;
0312 }
0313 if (sec.count() <= opt.noiseThreshold && sec.xSize() <= opt.xMinBinSize &&
0314 sec.ySize() <= opt.yMinBinSize) {
0315 std::cerr << "Accepted section: \n";
0316 return Accept;
0317 }
0318
0319 return Drill;
0320 };
0321
0322 std::vector<HoughAccumulatorSection> sectionsStack;
0323 sectionsStack.push_back(std::move(section));
0324
0325 std::vector<HoughAccumulatorSection> results;
0326
0327
0328 exploreHoughParametersSpace(sectionsStack, measurements, opt, results);
0329
0330
0331 BOOST_CHECK(!sStat.empty());
0332
0333
0334 BOOST_CHECK(sectionsStack.empty());
0335
0336
0337 BOOST_REQUIRE_EQUAL(results.size(), 2);
0338 BOOST_CHECK_EQUAL(results[0].xSize(), 2.5);
0339 BOOST_CHECK_EQUAL(results[0].count(), 3);
0340 BOOST_CHECK_EQUAL(results[1].ySize(), 2.5);
0341 BOOST_CHECK_EQUAL(results[1].count(), 3);
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355 BOOST_CHECK_EQUAL(sStat[1].nSections, 2);
0356 BOOST_CHECK_EQUAL(sStat[1].area, 100.0);
0357 BOOST_CHECK_EQUAL(sStat[1].nLines, 9);
0358 BOOST_CHECK_EQUAL(sStat[1].discardedByThresholdCut, 1);
0359 BOOST_CHECK_EQUAL(sStat[1].discardedByCrossingCut, 1);
0360
0361
0362
0363
0364 BOOST_CHECK_EQUAL(sStat[2].nSections, 2);
0365 BOOST_CHECK_EQUAL(sStat[2].area, 25.0);
0366 BOOST_CHECK_EQUAL(sStat[2].nLines, 7);
0367 BOOST_CHECK_EQUAL(sStat[2].discardedByThresholdCut, 2);
0368 BOOST_CHECK_EQUAL(sStat[2].discardedByCrossingCut, 4);
0369
0370
0371
0372
0373
0374
0375 BOOST_CHECK_EQUAL(sStat[3].nSections, 2);
0376 BOOST_CHECK_EQUAL(sStat[3].area, 12.5);
0377 BOOST_CHECK_EQUAL(sStat[3].nLines, 6);
0378 BOOST_CHECK_EQUAL(sStat[3].discardedByThresholdCut, 1);
0379 BOOST_CHECK_EQUAL(sStat[3].discardedByCrossingCut, 1);
0380 }
0381
0382 BOOST_AUTO_TEST_CASE(test_drill_and_expand_logic) {
0383
0384
0385
0386
0387
0388 std::vector<LineParameters> measurements = {
0389 {0.0f, -3.5f},
0390 {2.0f, -4.0f},
0391 {0.0f, 0.5f}
0392 };
0393
0394 TestExplorationOptions<LineParameters> opt;
0395 opt.xMinBinSize = 6.0f;
0396 opt.yMinBinSize = 6.0f;
0397 opt.noiseThreshold = 3;
0398 opt.threshold = 2;
0399 opt.min_division_level = 0;
0400 opt.expandX = 1.5;
0401 opt.expandY = 1.5;
0402 opt.lineFunctor = [](const LineParameters &p, float arg) {
0403 return p.slope * arg + p.intercept;
0404 };
0405
0406 HoughAccumulatorSection section(8.0f, 8.0f, -4.0f, -4.0f, 0);
0407 section.updateDecision(HoughAccumulatorSection::Decision::DrillAndExpand);
0408 section.indices() = {0, 1, 2};
0409
0410 std::map<int, Stats> sStat;
0411
0412 opt.decisionFunctor = [&sStat, &opt](const HoughAccumulatorSection &sec,
0413 const std::vector<LineParameters> &mes) {
0414 using enum HoughAccumulatorSection::Decision;
0415 if (sec.count() < opt.threshold) {
0416 sStat[sec.divisionLevel()].discardedByThresholdCut += 1;
0417 return Discard;
0418 }
0419 if (sec.count() < 3 * opt.threshold &&
0420 !passIntersectionsCheck(sec, mes, opt.lineFunctor,
0421 opt.threshold * (opt.threshold - 1))) {
0422 sStat[sec.divisionLevel()].discardedByCrossingCut += 1;
0423 return Discard;
0424 }
0425
0426 sStat[sec.divisionLevel()].area += sec.xSize() * sec.ySize();
0427 sStat[sec.divisionLevel()].nSections += 1;
0428 sStat[sec.divisionLevel()].nLines += sec.count();
0429
0430 if (sec.divisionLevel() <= opt.min_division_level) {
0431 return DrillAndExpand;
0432 }
0433 if (sec.count() <= opt.noiseThreshold && sec.xSize() <= opt.xMinBinSize &&
0434 sec.ySize() <= opt.yMinBinSize) {
0435 return Accept;
0436 }
0437 return DrillAndExpand;
0438 };
0439
0440 std::vector<HoughAccumulatorSection> sectionsStack;
0441 sectionsStack.push_back(std::move(section));
0442 std::vector<HoughAccumulatorSection> results;
0443
0444 exploreHoughParametersSpace(sectionsStack, measurements, opt, results);
0445
0446 BOOST_CHECK(sectionsStack.empty());
0447
0448 BOOST_REQUIRE_EQUAL(results.size(), 1);
0449 BOOST_CHECK_EQUAL(results[0].xSize(), 6.0);
0450 BOOST_CHECK_EQUAL(results[0].ySize(), 6.0);
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467 BOOST_CHECK_EQUAL(sStat[1].discardedByThresholdCut, 1);
0468 BOOST_CHECK_EQUAL(sStat[1].discardedByCrossingCut, 2);
0469 BOOST_CHECK_EQUAL(sStat[1].nSections, 1);
0470 BOOST_CHECK_EQUAL(sStat[1].area, 36.0);
0471 BOOST_CHECK_EQUAL(sStat[1].nLines, 3);
0472 }
0473
0474 BOOST_AUTO_TEST_SUITE_END()
0475
0476 }